Bolt  1.3
C++ template library with support for OpenCL
transform_iterator.h
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 
18 // (C) Copyright David Abrahams 2002.
19 // (C) Copyright Jeremy Siek 2002.
20 // (C) Copyright Thomas Witt 2002.
21 // Distributed under the Boost Software License, Version 1.0. (See
22 // accompanying file BOOST_LICENSE_1_0.txt or copy at
23 // http://www.boost.org/LICENSE_1_0.txt)
24 #ifndef BOLT_TRANSFORM_ITERATOR_H
25 #define BOLT_TRANSFORM_ITERATOR_H
26 
27 #include <type_traits>
28 
29 #include <bolt/cl/iterator/iterator_adaptor.h>
30 #include <bolt/cl/iterator/iterator_facade.h>
32 #include <bolt/cl/device_vector.h>
33 
34 
35 namespace bolt
36 {
37 namespace cl
38 {
39 
41  : public fancy_iterator_tag
42  { };
43 
142  template <class UnaryFunction, class Iterator, class Reference = use_default, class Value = use_default>
144 
145  namespace detail
146  {
147  // Compute the iterator_adaptor instantiation to be used for transform_iterator
148  template <class UnaryFunc, class Iterator, class Reference, class Value>
150  {
151  private:
152  // By default, dereferencing the iterator yields the same as
153  // the function.
154  typedef typename bolt::cl::detail::ia_dflt_help <
155  Reference
156  , std::result_of< const UnaryFunc(typename std::iterator_traits<Iterator>::reference) >
157  >::type reference;
158 
159  // To get the default for Value: remove any reference on the
160  // result type, but retain any constness to signal
161  // non-writability. Note that if we adopt Thomas' suggestion
162  // to key non-writability *only* on the Reference argument,
163  // we'd need to strip constness here as well.
164  typedef typename bolt::cl::detail::ia_dflt_help<
165  Value
166  , std::remove_reference<reference>
167  >::type cv_value_type;
168 
169  public:
170  typedef iterator_adaptor<
172  , Iterator
173  , cv_value_type
174  , use_default // Leave the traversal category alone
175  , reference
176  , std::ptrdiff_t
177  > type;
178  };
179  }// namespace detail
180 
181  template <class UnaryFunc, class Iterator, class Reference, class Value>
183  : public bolt::cl::detail::transform_iterator_base<UnaryFunc, Iterator, Reference, Value>::type
184  {
185  typedef typename
187  super_t;
188 
189  friend class iterator_core_access;
190 
191  public:
192  typedef transform_iterator_tag iterator_category;
193  typedef typename bolt::cl::iterator_category<Iterator>::type memory_system;
195  //
196  typedef UnaryFunc unary_func;
197  typedef typename std::iterator_traits<Iterator>::value_type value_type;
198  typedef std::ptrdiff_t difference_type;
199  typedef typename std::iterator_traits<Iterator>::pointer pointer;
201  transform_iterator() { }
202 
203  transform_iterator(Iterator const& x, UnaryFunc f)
204  : super_t(x), m_f(f) { }
205 
206  explicit transform_iterator(Iterator const& x)
207  : super_t(x)
208  {
209  }
210 
211  template <
212  class OtherUnaryFunction
213  , class OtherIterator
214  , class OtherReference
215  , class OtherValue>
219  : super_t(t.base()), m_f(t.functor())
220  { }
221 
222 
223  value_type* getPointer()
224  {
225  Iterator base_iterator = this->base_reference();
226  return &(*base_iterator);
227  }
228 
229  const value_type* getPointer() const
230  {
231  Iterator base_iterator = this->base_reference();
232  return &(*base_iterator);
233  }
234 
235  UnaryFunc functor() const
236  { return m_f; }
237 
238  struct Payload
239  {
240  int m_Index;
241  int m_Ptr1[ 3 ]; // Represents device pointer, big enough for 32 or 64bit
242  UnaryFunc m_f;
243  };
244 
245  /*TODO - RAVI Probably I can acheive this using friend class device_vector. But the problem would be
246  multiple defintions of functions like advance()*/
247  template<typename Container >
248  Container& getContainer( ) const
249  {
250  return this->base().getContainer( );
251  }
252 
253  const Payload gpuPayload( ) const
254  {
255  Payload payload = { 0/*m_Index*/, { 0, 0, 0 } };
256  return payload;
257  }
258 
259  /*TODO - This should throw a compilation error if the Iterator is of type std::vector*/
260  const difference_type gpuPayloadSize( ) const
261  {
262  cl_int l_Error = CL_SUCCESS;
263  //::cl::Device which_device;
264  //l_Error = m_it.getContainer().m_commQueue.getInfo(CL_QUEUE_DEVICE,&which_device );
265  //TODO - fix the device bits
266  cl_uint deviceBits = 32;// = which_device.getInfo< CL_DEVICE_ADDRESS_BITS >( );
267  // Size of index and pointer
268  cl_uint szUF = sizeof(UnaryFunc);
269  szUF = (szUF+3) &(~3);
270  difference_type payloadSize = sizeof( int ) + ( deviceBits >> 3 ) + szUF;
271 
272  // 64bit devices need to add padding for 8 byte aligned pointer
273  if( deviceBits == 64 )
274  payloadSize += 4;
275 
276  return payloadSize;
277  }
278 
279  int setKernelBuffers(int arg_num, ::cl::Kernel &kernel) const
280  {
281  /*Next set the Argument Iterator*/
282  arg_num = this->base().setKernelBuffers(arg_num, kernel);
283  return arg_num;
284  }
285  private:
286  typename super_t::reference dereference() const
287  { return m_f(*this->base()); }
288 
289  UnaryFunc m_f;
290  };
291 
292  template <class UnaryFunc, class Iterator>
294  make_transform_iterator(Iterator it, UnaryFunc fun)
295  {
297  }
298 
299  // Version which allows explicit specification of the UnaryFunc
300  // type.
301  //
302  // This generator is not provided if UnaryFunc is a function
303  // pointer type, because it's too dangerous: the default-constructed
304  // function pointer in the iterator be 0, leading to a runtime
305  // crash.
306  template <class UnaryFunc, class Iterator>
307  typename std::enable_if<
308  std::is_class<UnaryFunc>::value // We should probably find a cheaper test than is_class<>
310  >::type
311  make_transform_iterator(Iterator it)
312  {
313  return transform_iterator<UnaryFunc, Iterator>(it, UnaryFunc());
314  }
315 
316  // This string represents the device side definition of the Transform Iterator template
317  static std::string deviceTransformIteratorTemplate =
318  bolt::cl::deviceVectorIteratorTemplate +
319  std::string("#if !defined(BOLT_CL_TRANSFORM_ITERATOR) \n#define BOLT_CL_TRANSFORM_ITERATOR \n") +
320  STRINGIFY_CODE(
321  namespace bolt { namespace cl { \n
322  template< typename UnaryFunc, typename Iterator > \n
323  class transform_iterator \n
324  { \n
325  public: \n
326  typedef int iterator_category; \n
327  typedef typename UnaryFunc::result_type value_type; \n
328  typedef typename Iterator::value_type base_type; \n
329  typedef int size_type; \n
330 
331  transform_iterator( size_type init ): m_StartIndex( init ), m_Ptr( 0 ) \n
332  {} \n
333 
334  void init( global base_type* ptr )\n
335  { \n
336  m_Ptr = ptr; \n
337  } \n
338 
339  value_type operator[]( size_type threadID ) const \n
340  { \n
341  base_type tmp = m_Ptr[ m_StartIndex + threadID ]; \n
342  return m_f(tmp);\n
343  } \n
344 
345  value_type operator*( ) const \n
346  { \n
347  base_type tmp = m_Ptr[ m_StartIndex + threadID ]; \n
348  return m_f( tmp ); \n
349  } \n
350 
351  size_type m_StartIndex; \n
352  global base_type* m_Ptr; \n
353  UnaryFunc m_f; \n
354  }; \n
355  } } \n
356  )
357  + std::string("#endif \n");
358 
359 } // namespace cl
360 } // namespace bolt
361 
362 #endif // BOLT_TRANSFORM_ITERATOR_H