Bolt  1.3
C++ template library with support for OpenCL
counting_iterator.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 #pragma once
18 #if !defined( BOLT_CL_COUNTING_ITERATOR_H )
19 #define BOLT_CL_COUNTING_ITERATOR_H
20 
21 #include "bolt/cl/device_vector.h"
23 #include <boost/iterator/iterator_facade.hpp>
24 
29 namespace bolt {
30 namespace cl {
31 
33  : public fancy_iterator_tag
34  { // identifying tag for random-access iterators
35  };
36 
74  template< typename value_type >
75  class counting_iterator: public boost::iterator_facade< counting_iterator< value_type >, value_type,
76  counting_iterator_tag, value_type, int >
77  {
78  public:
79 
80  typedef typename boost::iterator_facade< counting_iterator< value_type >, value_type,
81  counting_iterator_tag, value_type, int >::difference_type difference_type;
83  typedef std::random_access_iterator_tag memory_system;
84  typedef value_type * pointer;
85 
86  struct Payload
87  {
88  value_type m_Value;
89  };
90 
91  // Basic constructor requires a reference to the container and a positional element
92  counting_iterator( value_type init, const control& ctl = control::getDefault( ) ):
93  m_initValue( init ),
94  m_Index( 0 )
95  {
96  const ::cl::CommandQueue& m_commQueue = ctl.getCommandQueue( );
97 
98  // We want to use the context from the passed in commandqueue to initialize our buffer
99  cl_int l_Error = CL_SUCCESS;
100  ::cl::Context l_Context = m_commQueue.getInfo< CL_QUEUE_CONTEXT >( &l_Error );
101  V_OPENCL( l_Error, "device_vector failed to query for the context of the ::cl::CommandQueue object" );
102 
103  m_devMemory = ::cl::Buffer( l_Context, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR | CL_MEM_COPY_HOST_PTR,
104  1 * sizeof( value_type ), &m_initValue );
105  }
106 
107  // This copy constructor allows an iterator to convert into a const_iterator, but not vica versa
108  template< typename OtherType >
109  counting_iterator( const counting_iterator< OtherType >& rhs ): m_devMemory( rhs.m_devMemory ),
110  m_Index( rhs.m_Index ), m_initValue( rhs.m_initValue )
111  {
112  }
113 
114  value_type* getPointer()
115  {
116  return &m_initValue;
117  }
118 
119  const value_type* getPointer() const
120  {
121  return &m_initValue;
122  }
123 
124  counting_iterator< value_type >& operator= ( const counting_iterator< value_type >& rhs )
125  {
126  if( this == &rhs )
127  return *this;
128 
129  m_devMemory = rhs.m_devMemory;
130  m_initValue = rhs.m_initValue;
131  m_Index = rhs.m_Index;
132  return *this;
133  }
134 
135  counting_iterator< value_type >& operator+= ( const difference_type & n )
136  {
137  advance( n );
138  return *this;
139  }
140 
141  const counting_iterator< value_type > operator+ ( const difference_type & n ) const
142  {
143  counting_iterator< value_type > result( *this );
144  result.advance( n );
145  return result;
146  }
147 
148  const ::cl::Buffer& getBuffer( ) const
149  {
150  return m_devMemory;
151  }
152 
153  const counting_iterator< value_type > & getContainer( ) const
154  {
155  return *this;
156  }
157 
158  const counting_iterator< value_type > & base( ) const
159  {
160  return *this;
161  }
162 
163  Payload gpuPayload( ) const
164  {
165  Payload payload = { m_initValue };
166  return payload;
167  }
168 
169  const difference_type gpuPayloadSize( ) const
170  {
171  return sizeof( Payload );
172  }
173 
174  int setKernelBuffers(int arg_num, ::cl::Kernel &kernel) const
175  {
176  const ::cl::Buffer &buffer = getContainer().getBuffer();
177  kernel.setArg(arg_num, buffer );
178  arg_num++;
179  return arg_num;
180  }
181 
182  difference_type distance_to( const counting_iterator< value_type >& rhs ) const
183  {
184  //return static_cast< typename iterator_facade::difference_type >( 1 );
185  return rhs.m_Index - m_Index;
186  }
187 
188  // Public member variables
189  difference_type m_Index;
190 
191  private:
192  // Implementation detail of boost.iterator
193  friend class boost::iterator_core_access;
194 
195  // Used for templatized copy constructor and the templatized equal operator
196  template < typename > friend class counting_iterator;
197 
198  // For a counting_iterator, do nothing on an advance
199  void advance(difference_type n )
200  {
201  m_Index += n;
202  }
203 
204  void increment( )
205  {
206  advance( 1 );
207  }
208 
209  void decrement( )
210  {
211  advance( -1 );
212  }
213 
214  template< typename OtherType >
215  bool equal( const counting_iterator< OtherType >& rhs ) const
216  {
217  bool sameIndex = (rhs.m_initValue == m_initValue) && (rhs.m_Index == m_Index);
218 
219  return sameIndex;
220  }
221 
222  typename boost::iterator_facade< counting_iterator< value_type >, value_type,
223  counting_iterator_tag, value_type, int >::reference dereference( ) const
224  {
225  return m_initValue + m_Index;
226  }
227 
228  ::cl::Buffer m_devMemory;
229  value_type m_initValue;
230  };
231  //)
232 
233  // This string represents the device side definition of the counting_iterator template
234  static std::string deviceCountingIterator =
235  std::string("#if !defined(BOLT_CL_COUNTING_ITERATOR) \n#define BOLT_CL_COUNTING_ITERATOR \n") +
236  STRINGIFY_CODE(
237  namespace bolt { namespace cl { \n
238  template< typename T > \n
239  class counting_iterator \n
240  { \n
241  public: \n
242  typedef int iterator_category; // device code does not understand std:: tags \n
243  typedef T value_type; \n
244  typedef T base_type; \n
245  typedef size_t difference_type; \n
246  typedef size_t size_type; \n
247  typedef T* pointer; \n
248  typedef T& reference; \n
249 
250  counting_iterator( value_type init ): m_StartIndex( init ), m_Ptr( 0 ) \n
251  {}; \n
252 
253  void init( global value_type* ptr ) \n
254  { \n
255 
256  //m_Ptr = ptr; \n
257  }; \n
258 
259  value_type operator[]( size_type threadID ) const \n
260  { \n
261  return m_StartIndex + threadID; \n
262  } \n
263 
264  value_type operator*( ) const \n
265  { \n
266  return m_StartIndex + threadID; \n
267  } \n
268 
269  value_type m_StartIndex; \n
270  }; \n
271  } } \n
272  )
273  + std::string("#endif \n");
274 
275 
276  template< typename Type >
277  counting_iterator< Type > make_counting_iterator( Type constValue )
278  {
279  counting_iterator< Type > tmp( constValue );
280  return tmp;
281  }
282 
283 }
284 }
285 
287 BOLT_CREATE_CLCODE( bolt::cl::counting_iterator< int >, bolt::cl::deviceCountingIterator );
288 
293 
294 #endif