Bolt  1.1
C++ template library with support for OpenCL
device_vector.h
Go to the documentation of this file.
1 /***************************************************************************
2 * Copyright 2012 - 2013 Advanced Micro Devices, Inc.
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 {
58  : public std::random_access_iterator_tag
59  { // identifying tag for random-access iterators
60  };
61 
70 template< typename T, template < typename, int RANK = 1 > class CONT= concurrency::array >
72 {
73  typedef T* naked_pointer;
74  typedef const T* const_naked_pointer;
75 
76 public:
77  // Useful typedefs specific to this container
78  typedef T value_type;
79  typedef ptrdiff_t difference_type;
80  typedef difference_type distance_type;
81  typedef size_t size_type;
82 
83  // These typedefs help define the template template parameter that represents our AMP container
84  typedef CONT< T > container_type;
85  typedef concurrency::array_view< T > arrayview_type;
86  typedef concurrency::array< T > array_type;
87 
88  typedef naked_pointer pointer;
89  typedef const_naked_pointer const_pointer;
90 
99  template< typename Container >
101  {
102  public:
103  reference_base( Container& rhs, size_type index ): m_Container( rhs ), m_Index( index )
104  {}
105 
106  // Automatic type conversion operator to turn the reference object into a value_type
107  operator value_type( ) const
108  {
109  arrayview_type av( *m_Container.m_devMemory );
110  value_type &result = av[static_cast< int >( m_Index )];
111 
112  return result;
113  }
114 
115  reference_base< Container >& operator=( const value_type& rhs )
116  {
117  arrayview_type av( *m_Container.m_devMemory );
118  av[static_cast< int >( m_Index )] = rhs;
119 
120  return *this;
121  }
122 
125  Container& getContainer( ) const
126  {
127  return m_Container;
128  }
129 
132  size_type getIndex() const
133  {
134  return m_Index;
135  }
136 
137  private:
138  Container& m_Container;
139  size_type m_Index;
140  };
141 
146 
147  template< typename Container >
149  {
150  public:
151  const_reference_base( const Container& rhs, size_type index ): m_Container( rhs ), m_Index( index )
152  {}
153 
154  // Automatic type conversion operator to turn the reference object into a value_type
155  operator value_type( ) const
156  {
157  arrayview_type av( *m_Container.m_devMemory );
158  value_type &result = av[static_cast< int >( m_Index )];
159 
160  return result;
161  }
162 
163  const_reference_base< const Container >& operator=( const value_type& rhs )
164  {
165  arrayview_type av( *m_Container.m_devMemory );
166  av[static_cast< int >( m_Index )] = rhs;
167 
168  return *this;
169  }
170 
173  const Container& getContainer( ) const
174  {
175  return m_Container;
176  }
177 
180  size_type getIndex() const
181  {
182  return m_Index;
183  }
184 
185  private:
186  const Container& m_Container;
187  size_type m_Index;
188  };
189 
196 
197  // Handy for the reference class to get at the wrapped ::cl objects
198  friend class reference;
199 
208  template< typename Container >
209  class iterator_base: public boost::iterator_facade< iterator_base< Container >,
210  value_type, device_vector_tag, typename device_vector::reference >
211  {
212  public:
213 
214  // Basic constructor requires a reference to the container and a positional element
215  iterator_base( Container& rhs, size_type index ): m_Container( rhs ), m_Index( index )
216  {}
217 
218  // This copy constructor allows an iterator to convert into a const_iterator, but not vica versa
219  template< typename OtherContainer >
221  m_Container( rhs.m_Container ), m_Index( rhs.m_Index )
222  {}
223 
224  // This copy constructor allows an iterator to convert into a const_iterator, but not vica versa
225  //template< typename Container >
227  {
228  m_Container = rhs.m_Container;
229  m_Index = rhs.m_Index;
230  return *this;
231  }
232 
233  iterator_base< Container >& operator+= ( const difference_type & n )
234  {
235  advance( n );
236  return *this;
237  }
238 
239  const iterator_base< Container > operator+ ( const difference_type & n ) const
240  {
241  iterator_base< Container > result(*this);
242  result.advance(n);
243  return result;
244  }
245 
246  Container& getContainer( ) const
247  {
248  return m_Container;
249  }
250 
251  size_type getIndex() const
252  {
253  return m_Index;
254  }
255 
256 
257 
258  difference_type distance_to( const iterator_base< Container >& rhs ) const
259  {
260  return ( rhs.m_Index - m_Index );
261  }
262  size_type m_Index;
263  private:
264  // Implementation detail of boost.iterator
265  friend class boost::iterator_core_access;
266 
267  // Handy for the device_vector erase methods
268  friend class device_vector< value_type >;
269 
270  // Used for templatized copy constructor and the templatized equal operator
271  template < typename > friend class iterator_base;
272 
273  void advance( difference_type n )
274  {
275  m_Index += n;
276  }
277 
278  void increment( )
279  {
280  advance( 1 );
281  }
282 
283  void decrement( )
284  {
285  advance( -1 );
286  }
287 
288 
289 
290  template< typename OtherContainer >
291  bool equal( const iterator_base< OtherContainer >& rhs ) const
292  {
293  bool sameIndex = rhs.m_Index == m_Index;
294  bool sameContainer = (&m_Container == &rhs.m_Container );
295 
296  return ( sameIndex && sameContainer );
297  }
298 
299  reference dereference( ) const
300  {
301  return m_Container[ m_Index ];
302  }
303 
304  Container& m_Container;
305 
306  };
307 
308 
314  template< typename Container >
315  class reverse_iterator_base: public boost::iterator_facade< reverse_iterator_base< Container >,
316  value_type, std::random_access_iterator_tag, typename device_vector::reference >
317  {
318  public:
319 
320  // Basic constructor requires a reference to the container and a positional element
321  reverse_iterator_base( Container& lhs, size_type index ): m_Container( lhs ), m_Index( index-1 )
322  {}
323 
324  // This copy constructor allows an iterator to convert into a const_iterator, but not vica versa
325  template< typename OtherContainer >
327  m_Container( lhs.m_Container ), m_Index( lhs.m_Index-1 )
328  {}
329 
330  // This copy constructor allows an iterator to convert into a const_iterator, but not vica versa
331  //template< typename Container >
333  {
334  m_Container = lhs.m_Container;
335  m_Index = lhs.m_Index;
336  return *this;
337  }
338 
339  reverse_iterator_base< Container >& operator+= ( const difference_type & n )
340  {
341  advance( -n );
342  return *this;
343  }
344 
345  const reverse_iterator_base< Container > operator+ ( const difference_type & n ) const
346  {
348  result.advance(-n);
349  return result;
350  }
351 
352  size_type getIndex() const
353  {
354  return m_Index;
355  }
356 
357  Container& getContainer( ) const
358  {
359  return m_Container;
360  }
361 
362 
363  difference_type distance_to( const reverse_iterator_base< Container >& lhs ) const
364  {
365  return static_cast< difference_type >( m_Index - lhs.m_Index );
366  }
367 
368  private:
369  // Implementation detail of boost.iterator
370  friend class boost::iterator_core_access;
371 
372  // Handy for the device_vector erase methods
373  friend class device_vector< value_type >;
374 
375  // Used for templatized copy constructor and the templatized equal operator
376  template < typename > friend class reverse_iterator_base;
377 
378  void advance( difference_type n )
379  {
380  m_Index += n;
381  }
382 
383  void increment( )
384  {
385  advance( -1 );
386  }
387 
388  void decrement( )
389  {
390  advance( 1 );
391  }
392 
393 
394 
395  template< typename OtherContainer >
396  bool equal( const reverse_iterator_base< OtherContainer >& lhs ) const
397  {
398  bool sameIndex = lhs.m_Index == m_Index;
399  bool sameContainer = (&m_Container == &lhs.m_Container );
400 
401  return ( sameIndex && sameContainer );
402  }
403 
404  reference dereference( ) const
405  {
406  return m_Container[ m_Index ];
407  }
408 
409  Container& m_Container;
410  size_type m_Index;
411 
412  };
413 
414 
418 
422 
426 
430 
431 
437  device_vector( control& ctl = control::getDefault( ) ): m_Size( 0 ), m_devMemory( NULL )
438  { }
439 
450  device_vector( size_type newSize, const value_type& initValue = value_type( ), bool init = true,
451  control& ctl = control::getDefault( ) ): m_Size( newSize )
452  {
453  static_assert( std::is_same< array_type, container_type >::value,
454  "This constructor is only valid for concurrency::array types. concurrency::array_views should use a "
455  "constructor that accepts host backing store" );
456 
457  if( m_Size > 0 )
458  {
459  m_devMemory = new container_type( static_cast< int >( m_Size ) );
460 
461  if( init )
462  {
463  arrayview_type m_devMemoryAV( *m_devMemory );
464  Concurrency::parallel_for_each( m_devMemoryAV.extent, [=](Concurrency::index<1> idx) restrict(amp)
465  {
466  m_devMemoryAV[idx] = initValue;
467  }
468  );
469  }
470  }
471  else
472  {
473  m_devMemory = NULL;
474  }
475  }
476 
486  template< typename InputIterator >
487  device_vector( const InputIterator begin, size_type newSize, control& ctl = control::getDefault( ),
488  typename std::enable_if< !std::is_integral< InputIterator >::value &&
489  std::is_same< array_type, container_type >::value>::type* = 0 ) : m_Size( newSize )
490  {
491  static_assert( std::is_same< array_type, container_type >::value,
492  "This constructor is only valid for concurrency::array types. concurrency::array_views should use a "
493  "constructor that accepts containers" );
494 
495  concurrency::extent<1> ext( static_cast< int >( m_Size ) );
496  m_devMemory = new container_type( ext, begin, ctl.getAccelerator( ).default_view );
497  };
498 
509  template< typename InputIterator >
510  device_vector( const InputIterator begin, size_type newSize, bool discard = false, control& ctl = control::getDefault( ),
511  typename std::enable_if< !std::is_integral< InputIterator >::value &&
512  std::is_same< arrayview_type, container_type >::value>::type* = 0 ) : m_Size( newSize )
513  {
514  concurrency::extent<1> ext( static_cast< int >( m_Size ) );
515  m_devMemory = new container_type( ext, &begin[ 0 ] );
516  };
517 
524  template< typename Container >
525  device_vector( Container& cont, bool discard = false, control& ctl = control::getDefault( ) ): m_Size( cont.size( ) )
526  {
527  static_assert( std::is_same< arrayview_type, container_type >::value,
528  "This constructor is only valid for concurrency::array_view types" );
529 
530  concurrency::extent<1> ext( static_cast< int >( m_Size ) );
531  m_devMemory = new container_type( ext, cont );
532 
533  // TODO: I can't get this constructor to properly resolve
534  //m_devMemory = new container_type( ext, cont, discard );
535  };
536 
543  template< typename InputIterator >
544  device_vector( const InputIterator begin, const InputIterator end, control& ctl = control::getDefault( ),
545  typename std::enable_if< !std::is_integral< InputIterator >::value &&
546  std::is_same< array_type, container_type >::value>::type* = 0 )
547  {
548  static_assert( std::is_same< array_type, container_type >::value,
549  "This constructor is only valid for concurrency::array types. concurrency::array_views should use a "
550  "constructor that accepts containers" );
551 
552  m_Size = std::distance( begin, end );
553 
554  concurrency::extent<1> ext( static_cast< int >( m_Size ) );
555 
556  m_devMemory = new container_type( ext, begin, end, ctl.getAccelerator().default_view );
557  };
558 
565  template< typename InputIterator >
566  device_vector( const InputIterator begin, const InputIterator end, bool discard = false, control& ctl = control::getDefault( ),
567  typename std::enable_if< !std::is_integral< InputIterator >::value &&
568  std::is_same< arrayview_type, container_type >::value>::type* = 0 )
569  {
570  m_Size = std::distance( begin, end );
571 
572  concurrency::extent<1> ext( static_cast< int >( m_Size ) );
573 
574  m_devMemory = new container_type( ext, &begin[ 0 ] );
575  };
576 
581  device_vector( container_type& rhs, control& ctl = control::getDefault( ) ): m_devMemory( rhs )
582  {
583  m_Size = capacity( );
584  };
585 
586  //destructor for device_vector
587  ~device_vector()
588  {
589  if (m_devMemory != NULL)
590  {
591  delete( m_devMemory );
592  }
593  }
594 
595  // Member functions
596 
597 
605  arrayview_type getBuffer( ) const
606  {
607  concurrency::extent<1> ext( static_cast< int >( m_Size ) );
608  return m_devMemory->view_as( ext );
609  }
610 
611 
623  void resize( size_type reqSize, const value_type& val = value_type( ) )
624  {
625  static_assert( std::is_same< array_type, container_type >::value,
626  "This member function is only valid for concurrency::array types.");
627  size_type cap = capacity( );
628 
629  if( reqSize == cap )
630  return;
631 
632  //TODO - Add if statement for max size allowed in array class
633  container_type* l_tmpBuffer = new container_type((int)reqSize);
634  if( m_Size > 0 )
635  {
636  //1622 Arrays are logically considered to be value types in that when an array is copied to another array,
637  //a deep copy is performed. Two arrays never point to the same data.
638  //m_Size data elements are copied
639 
640  if( reqSize > m_Size )
641  {
642  m_devMemory->copy_to(*l_tmpBuffer);
643  arrayview_type l_tmpBufferSectionAV =
644  l_tmpBuffer->section((int)m_Size, (int)(reqSize - m_Size));
645  concurrency::parallel_for_each(l_tmpBufferSectionAV.extent, [=](Concurrency::index<1> idx) restrict(amp)
646  {
647  l_tmpBufferSectionAV[idx] = val;
648  });
649  }
650  else
651  {
652  arrayview_type l_devMemoryAV = m_devMemory->section(0, (int)reqSize);
653  arrayview_type l_tmpBufferAV = l_tmpBuffer->section(0, (int)reqSize);
654  l_devMemoryAV.copy_to(l_tmpBufferAV);
655  }
656  }
657  else
658  {
659  arrayview_type l_tmpBufferAV(*l_tmpBuffer);
660  Concurrency::parallel_for_each(l_tmpBufferAV.extent, [=](Concurrency::index<1> idx) restrict(amp)
661  {
662  l_tmpBufferAV[idx] = val;
663  });
664  }
665 
666  // Remember the new size
667  m_Size = reqSize;
668  // delete the old buffer
669  delete(m_devMemory);
670  m_devMemory = l_tmpBuffer;
671  }
672 
677  size_type size( void ) const
678  {
679  return m_Size;
680  }
681 
685  /*size_type max_size( void ) const
686  {
687  cl_int l_Error = CL_SUCCESS;
688 
689  ::cl::Device l_Device = m_commQueue.getInfo< CL_QUEUE_DEVICE >( &l_Error );
690  V_OPENCL( l_Error, "device_vector failed to query for the device of the command queue" );
691 
692  size_type l_MaxSize = l_Device.getInfo< CL_DEVICE_MAX_MEM_ALLOC_SIZE >( &l_Error );
693  V_OPENCL( l_Error, "device_vector failed to query device for the maximum memory size" );
694 
695  return l_MaxSize / sizeof( value_type );
696  }*/
697 
709  void reserve( size_type reqSize )
710  {
711 
712  static_assert( std::is_same< array_type, container_type >::value,
713  "This member function is only valid for concurrency::array types.");
714  if( reqSize <= capacity( ) )
715  return;
716 
717  if( capacity() == 0 )
718  {
719  m_devMemory = new container_type((int)reqSize);
720  return;
721  }
722 
723  container_type* l_tmpBuffer = new container_type((int)reqSize);
724 
725  //size_type l_srcSize = m_devMemory->get_extent()[0];
726  m_devMemory->copy_to(*l_tmpBuffer);
727  delete(m_devMemory);
728  m_devMemory = l_tmpBuffer;
729  }
730 
736  size_type capacity( void ) const
737  {
738  if( m_devMemory != NULL )
739  {
740  Concurrency::extent<1> ext = m_devMemory->get_extent();
741  return ext.size();
742  }
743  return 0;
744  }
745 
752  {
753  static_assert( std::is_same< array_type, container_type >::value,
754  "This member function is only valid for concurrency::array types.");
755  if( m_Size == capacity( ) )
756  return;
757 
758  container_type* l_tmpBuffer = new container_type( static_cast< int >( size( ) ) );
759  arrayview_type l_devMemoryAV = m_devMemory->section( 0,(int)size() );
760  arrayview_type l_tmpBufferAV = l_tmpBuffer->section( 0,(int)size() );
761 
762  l_devMemoryAV.copy_to( l_tmpBufferAV );
763 
764  delete( m_devMemory );
765 
766  m_devMemory = l_tmpBuffer;
767  }
768 
772  reference operator[]( size_type n )
773  {
774  reference tmpRef( *this, n );
775 
776  return tmpRef;
777  }
778 
782  const_reference operator[]( size_type n ) const
783  {
784  const_reference tmpRef( *this, n );
785 
786  return tmpRef;
787  }
788 
792  iterator begin( void )
793  {
794  return iterator( *this, 0 );
795  }
796 
801  const_iterator begin( void ) const
802  {
803  return const_iterator( *this, 0 );
804  }
805 
811  const_iterator cbegin( void ) const
812  {
813  return const_iterator( *this, 0 );
814  }
815 
821  {
822  //static_assert( false, "Reverse iterators are not yet implemented" );
823  return reverse_iterator(*this,m_Size);
824  }
825 
832  {
833  //static_assert( false, "Reverse iterators are not yet implemented" );
834  return const_reverse_iterator(*this,m_Size);
835  }
836 
844  {
845  //static_assert( false, "Reverse iterators are not yet implemented" );
846  return const_reverse_iterator(*this,m_Size);
847  }
848 
852  iterator end( void )
853  {
854  return iterator( *this, m_Size );
855  }
856 
861  const_iterator end( void ) const
862  {
863  return const_iterator( *this, m_Size );
864  }
865 
871  const_iterator cend( void ) const
872  {
873  return const_iterator( *this, m_Size );
874  }
875 
881  {
882  return reverse_iterator( *this, 0 );
883  }
884 
891  {
892  return const_reverse_iterator( *this, 0 );
893  }
894 
902  {
903  return const_reverse_iterator( *this, 0 );
904  }
905 
909  reference front( void )
910  {
911  return (*begin());
912  }
913 
917  const_reference front( void ) const
918  {
919  return (*begin());
920  }
921 
925  reference back( void )
926  {
927  return ( *(end() - 1) );
928  }
929 
933  const_reference back( void ) const
934  {
935  return ( *(end() - 1) );
936  }
937 
938  //Yes you need the shared_array object.
939  //Ask kent for a better solution.
940  pointer data( void )
941  {
943  // below av.data(). It should anyway be freed in the UnMapBufferFunctor Functor
944 
945  synchronize( *this );
946 
947  arrayview_type av( *m_devMemory );
948  return av.data( );
949  }
950 
951  const_pointer data( void ) const
952  {
953  synchronize( *this );
954 
955  arrayview_type av( *m_devMemory );
956  return av.data( );
957  }
958 
962  void clear( void )
963  {
964  delete( m_devMemory );
965  m_devMemory = NULL;
966  m_Size = 0;
967  }
968 
972  bool empty( void ) const
973  {
974  return m_Size ? false: true;
975  }
976 
980  void push_back( const value_type& value )
981  {
982  if( m_Size > capacity( ) )
983  throw std::exception( "device_vector size can not be greater than capacity( )" );
984 
985  // Need to grow the vector to push new value.
986  // Vectors double their capacity on push_back if the array is not big enough.
987  if( m_Size == capacity( ) )
988  {
989  m_Size ? reserve( m_Size * 2 ) : reserve( 1 );
990  }
991 
992  arrayview_type av( *m_devMemory );
993  //insert(end(),value);
994  av[static_cast<int>( m_Size )] = value;
995  ++m_Size;
996  }
997 
1000  void pop_back( void )
1001  {
1002  if( m_Size > 0 )
1003  {
1004  --m_Size;
1005  }
1006  }
1007 
1011  void swap( device_vector& vec )
1012  {
1013  if( this == &vec )
1014  return;
1015 
1016  container_type* swapBuffer( m_devMemory );
1017  m_devMemory = vec.m_devMemory;
1018  vec.m_devMemory = swapBuffer;
1019 
1020  size_type sizeTmp = m_Size;
1021  m_Size = vec.m_Size;
1022  vec.m_Size = sizeTmp;
1023  }
1024 
1030  {
1031  if( &index.m_Container != this )
1032  throw std::exception( "Iterator is not from this container" );
1033 
1034  iterator l_End = end( );
1035  if( index.m_Index >= l_End.m_Index )
1036  throw std::exception( "Iterator is pointing past the end of this container" );
1037 
1038  size_type sizeRegion = l_End.m_Index - index.m_Index;
1039 
1040  arrayview_type av( *m_devMemory );
1041  naked_pointer ptrBuff = av.data();
1042  naked_pointer ptrBuffTemp = ptrBuff + index.m_Index;
1043  ::memmove( ptrBuffTemp, ptrBuffTemp + 1, (sizeRegion - 1)*sizeof( value_type ) );
1044 
1045  --m_Size;
1046 
1047  size_type newIndex = (m_Size < index.m_Index) ? m_Size : index.m_Index;
1048  return iterator( *this, newIndex );
1049  }
1050 
1057  {
1058  if(( &first.m_Container != this ) && ( &last.m_Container != this ) )
1059  throw std::exception( "Iterator is not from this container" );
1060 
1061  if( last.m_Index > m_Size )
1062  throw std::exception( "Iterator is pointing past the end of this container" );
1063 
1064  if( (first == begin( )) && (last == end( )) )
1065  {
1066  clear( );
1067  return iterator( *this, m_Size );
1068  }
1069 
1070  iterator l_End = end( );
1071  size_type sizeMap = l_End.m_Index - first.m_Index;
1072 
1073  arrayview_type av( *m_devMemory );
1074  naked_pointer ptrBuff = av.data();
1075  ptrBuff = ptrBuff + first.m_Index;
1076  size_type sizeErase = last.m_Index - first.m_Index;
1077  ::memmove( ptrBuff, ptrBuff + sizeErase, (sizeMap - sizeErase)*sizeof( value_type ) );
1078 
1079  m_Size -= sizeErase;
1080 
1081  size_type newIndex = (m_Size < last.m_Index) ? m_Size : last.m_Index;
1082  return iterator( *this, newIndex );
1083  }
1084 
1092  iterator insert( const_iterator index, const value_type& value )
1093  {
1094  if( &index.m_Container != this )
1095  throw std::exception( "Iterator is not from this container" );
1096 
1097  if( index.m_Index > m_Size )
1098  throw std::exception( "Iterator is pointing past the end of this container" );
1099 
1100  if( index.m_Index == m_Size )
1101  {
1102  push_back( value );
1103  return iterator( *this, index.m_Index );
1104  }
1105 
1106  // Need to grow the vector to insert a new value.
1107  // TODO: What is an appropriate growth strategy for GPU memory allocation? Exponential growth does not seem
1108  // right at first blush.
1109  if( m_Size == capacity( ) )
1110  {
1111  m_Size ? reserve( m_Size * 2 ) : reserve( 1 );
1112  }
1113 
1114  size_type sizeMap = (m_Size - index.m_Index) + 1;
1115 
1116  arrayview_type av( *m_devMemory );
1117  naked_pointer ptrBuff = av.data();
1118  ptrBuff = ptrBuff + index.m_Index;
1119 
1120  // Shuffle the old values 1 element down
1121  ::memmove( ptrBuff + 1, ptrBuff, (sizeMap - 1)*sizeof( value_type ) );
1122 
1123  // Write the new value in its place
1124  *ptrBuff = value;
1125 
1126  ++m_Size;
1127 
1128  return iterator( *this, index.m_Index );
1129  }
1130 
1138  void insert( const_iterator index, size_type n, const value_type& value )
1139  {
1140  static_assert( std::is_same< array_type, container_type >::value,
1141  "This member function is only valid for concurrency::array types.");
1142  if( &index.m_Container != this )
1143  throw std::exception( "Iterator is not from this container" );
1144 
1145  if( index.m_Index > m_Size )
1146  throw std::exception( "Iterator is pointing past the end of this container" );
1147 
1148  // Need to grow the vector to insert n new values
1149  if( ( m_Size + n ) > capacity( ) )
1150  {
1151  reserve( m_Size + n );
1152  }
1153 
1154  size_type sizeMap = (m_Size - index.m_Index) + n;
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 n element down.
1161  ::memmove( ptrBuff + n, ptrBuff, (sizeMap - n)*sizeof( value_type ) );
1162 
1163  // Copy the new value n times in the buffer.
1164  for( size_type i = 0; i < n; ++i )
1165  {
1166  ptrBuff[ i ] = value;
1167  }
1168 
1169  m_Size += n;
1170  }
1171 
1172  template< typename InputIterator >
1173  void insert( const_iterator index, InputIterator begin, InputIterator end )
1174  {
1175  if( &index.m_Container != this )
1176  throw std::exception( "Iterator is not from this container" );
1177 
1178  if( index.m_Index > m_Size )
1179  throw std::exception( "Iterator is pointing past the end of this container" );
1180 
1181  // Need to grow the vector to insert the range of new values
1182  size_type n = std::distance( begin, end );
1183  if( ( m_Size + n ) > capacity( ) )
1184  {
1185  reserve( m_Size + n );
1186  }
1187  size_type sizeMap = (m_Size - index.m_Index) + n;
1188 
1189  arrayview_type av( *m_devMemory );
1190  naked_pointer ptrBuff = av.data() + index.m_Index;
1191 
1192  // Shuffle the old values n element down.
1193  ::memmove( ptrBuff + n, ptrBuff, (sizeMap - n)*sizeof( value_type ) );
1194 
1195 #if( _WIN32 )
1196  std::copy( begin, end, stdext::checked_array_iterator< naked_pointer >( ptrBuff, n ) );
1197 #else
1198  std::copy( begin, end, ptrBuff );
1199 #endif
1200 
1201  m_Size += n;
1202  }
1203 
1209  void assign( size_type newSize, const value_type& value )
1210  {
1211  if( newSize > m_Size )
1212  {
1213  reserve( newSize );
1214  }
1215  m_Size = newSize;
1216 
1217  arrayview_type m_devMemoryAV( *m_devMemory );
1218  Concurrency::parallel_for_each( m_devMemoryAV.extent, [=](Concurrency::index<1> idx) restrict(amp)
1219  {
1220  m_devMemoryAV[idx] = value;
1221  }
1222  );
1223  }
1224 #if 1
1225 
1230  template<typename InputIterator>
1231  typename std::enable_if< std::_Is_iterator<InputIterator>::value, void>::type
1232  assign( InputIterator begin, InputIterator end )
1233  {
1234  size_type l_Count = std::distance( begin, end );
1235 
1236  if( l_Count > m_Size )
1237  {
1238  reserve( l_Count );
1239  }
1240  m_Size = l_Count;
1241  arrayview_type m_devMemoryAV( *m_devMemory );
1242  naked_pointer ptrBuff = m_devMemoryAV.data();
1243 #if( _WIN32 )
1244  std::copy( begin, end, stdext::checked_array_iterator< naked_pointer >( ptrBuff, m_Size ) );
1245 #else
1246  std::copy( begin, end, ptrBuff );
1247 #endif
1248  }
1249 #endif
1250 private:
1251 
1252  // These private routines make sure that the data that resides in the concurrency::array* object are
1253  // reflected back in the host memory. However, the complication is that the concurrency::array object
1254  // does not expose a synchronize method, whereas the concurrency::array_view does. These routines
1255  // differentiate between the two different containers
1256  void synchronize( device_vector< T, concurrency::array >& rhs )
1257  {
1258  };
1259 
1260  void synchronize( device_vector< T, concurrency::array_view >& rhs )
1261  {
1262  rhs.m_devMemory->synchronize( );
1263  };
1264 
1265  size_type m_Size;
1266  container_type* m_devMemory;
1267 };
1268 
1269 }
1270 }
1271 
1272 #endif