ViennaCL - The Vienna Computing Library  1.7.0
Free open-source GPU-accelerated linear algebra and solver library.
utils.hpp
Go to the documentation of this file.
1 #ifndef VIENNACL_DEVICE_SPECIFIC_UTILS_HPP
2 #define VIENNACL_DEVICE_SPECIFIC_UTILS_HPP
3 
4 /* =========================================================================
5  Copyright (c) 2010-2015, Institute for Microelectronics,
6  Institute for Analysis and Scientific Computing,
7  TU Wien.
8  Portions of this software are copyright by UChicago Argonne, LLC.
9 
10  -----------------
11  ViennaCL - The Vienna Computing Library
12  -----------------
13 
14  Project Head: Karl Rupp rupp@iue.tuwien.ac.at
15 
16  (A list of authors and contributors can be found in the manual)
17 
18  License: MIT (X11), see file LICENSE in the base directory
19 ============================================================================= */
20 
21 
26 #include <sstream>
27 
30 
32 #include "viennacl/ocl/forwards.h"
33 
35 
36 #include "viennacl/traits/size.hpp"
39 
40 #include "viennacl/tools/tools.hpp"
41 
42 namespace viennacl
43 {
44 namespace device_specific
45 {
46 namespace utils
47 {
48 
49 //CUDA Conversion
50 inline std::string opencl_source_to_cuda_source(std::string const & opencl_src)
51 {
52  std::string res = opencl_src;
53 
54  viennacl::tools::find_and_replace(res,"__attribute__","//__attribute__");
55 
56  //Pointer
57  viennacl::tools::find_and_replace(res, "__global float*", "float*");
58  viennacl::tools::find_and_replace(res, "__local float*", "float*");
59 
60  viennacl::tools::find_and_replace(res, "__global double*", "double*");
61  viennacl::tools::find_and_replace(res, "__local double*", "double*");
62 
63  //Qualifiers
64  viennacl::tools::find_and_replace(res,"__global","__device__");
65  viennacl::tools::find_and_replace(res,"__kernel","__global__");
66  viennacl::tools::find_and_replace(res,"__constant","__constant__");
67  viennacl::tools::find_and_replace(res,"__local","__shared__");
68 
69  //Indexing
70  viennacl::tools::find_and_replace(res,"get_num_groups(0)","gridDim.x");
71  viennacl::tools::find_and_replace(res,"get_num_groups(1)","gridDim.y");
72 
73  viennacl::tools::find_and_replace(res,"get_local_size(0)","blockDim.x");
74  viennacl::tools::find_and_replace(res,"get_local_size(1)","blockDim.y");
75 
76  viennacl::tools::find_and_replace(res,"get_group_id(0)","blockIdx.x");
77  viennacl::tools::find_and_replace(res,"get_group_id(1)","blockIdx.y");
78 
79  viennacl::tools::find_and_replace(res,"get_local_id(0)","threadIdx.x");
80  viennacl::tools::find_and_replace(res,"get_local_id(1)","threadIdx.y");
81 
82  viennacl::tools::find_and_replace(res,"get_global_id(0)","(blockIdx.x*blockDim.x + threadIdx.x)");
83  viennacl::tools::find_and_replace(res,"get_global_id(1)","(blockIdx.y*blockDim.y + threadIdx.y)");
84 
85  //Synchronization
86  viennacl::tools::find_and_replace(res,"barrier(CLK_LOCAL_MEM_FENCE)","__syncthreads()");
87  viennacl::tools::find_and_replace(res,"barrier(CLK_GLOBAL_MEM_FENCE)","__syncthreads()");
88 
89 
90  return res;
91 }
92 
93 static std::string numeric_type_to_string(scheduler::statement_node_numeric_type const & type){
94  switch (type)
95  {
96  //case scheduler::CHAR_TYPE: return "char";
97  //case scheduler::UCHAR_TYPE: return "unsigned char";
98  //case scheduler::SHORT_TYPE: return "short";
99  //case scheduler::USHORT_TYPE: return "unsigned short";
100  case scheduler::INT_TYPE: return "int";
101  case scheduler::UINT_TYPE: return "unsigned int";
102  case scheduler::LONG_TYPE: return "long";
103  case scheduler::ULONG_TYPE: return "unsigned long";
104  case scheduler::FLOAT_TYPE : return "float";
105  case scheduler::DOUBLE_TYPE : return "double";
106  default : throw generator_not_supported_exception("Unsupported Scalartype");
107  }
108 }
109 
110 
111 template<class Fun>
112 static typename Fun::result_type call_on_host_scalar(scheduler::lhs_rhs_element element, Fun const & fun){
113  assert(element.type_family == scheduler::SCALAR_TYPE_FAMILY && bool("Must be called on a host scalar"));
114  switch (element.numeric_type)
115  {
116  //case scheduler::CHAR_TYPE: return fun(element.host_char);
117  //case scheduler::UCHAR_TYPE: return fun(element.host_uchar);
118  //case scheduler::SHORT_TYPE: return fun(element.host_short);
119  //case scheduler::USHORT_TYPE: return fun(element.host_ushort);
120  case scheduler::INT_TYPE: return fun(element.host_int);
121  case scheduler::UINT_TYPE: return fun(element.host_uint);
122  case scheduler::LONG_TYPE: return fun(element.host_long);
123  case scheduler::ULONG_TYPE: return fun(element.host_ulong);
124  case scheduler::FLOAT_TYPE : return fun(element.host_float);
125  case scheduler::DOUBLE_TYPE : return fun(element.host_double);
126  default : throw generator_not_supported_exception("Unsupported Scalartype");
127  }
128 }
129 
130 template<class Fun>
131 static typename Fun::result_type call_on_scalar(scheduler::lhs_rhs_element element, Fun const & fun){
132  assert(element.type_family == scheduler::SCALAR_TYPE_FAMILY && bool("Must be called on a scalar"));
133  switch (element.numeric_type)
134  {
135  //case scheduler::CHAR_TYPE: return fun(*element.scalar_char);
136  //case scheduler::UCHAR_TYPE: return fun(*element.scalar_uchar);
137  //case scheduler::SHORT_TYPE: return fun(*element.scalar_short);
138  //case scheduler::USHORT_TYPE: return fun(*element.scalar_ushort);
139  case scheduler::INT_TYPE: return fun(*element.scalar_int);
140  case scheduler::UINT_TYPE: return fun(*element.scalar_uint);
141  case scheduler::LONG_TYPE: return fun(*element.scalar_long);
142  case scheduler::ULONG_TYPE: return fun(*element.scalar_ulong);
143  case scheduler::FLOAT_TYPE : return fun(*element.scalar_float);
144  case scheduler::DOUBLE_TYPE : return fun(*element.scalar_double);
145  default : throw generator_not_supported_exception("Unsupported Scalartype");
146  }
147 }
148 
149 template<class Fun>
150 static typename Fun::result_type call_on_vector(scheduler::lhs_rhs_element element, Fun const & fun){
151  assert(element.type_family == scheduler::VECTOR_TYPE_FAMILY && bool("Must be called on a vector"));
152  switch (element.numeric_type)
153  {
154  //case scheduler::CHAR_TYPE: return fun(*element.vector_char);
155  //case scheduler::UCHAR_TYPE: return fun(*element.vector_uchar);
156  //case scheduler::SHORT_TYPE: return fun(*element.vector_short);
157  //case scheduler::USHORT_TYPE: return fun(*element.vector_ushort);
158  case scheduler::INT_TYPE: return fun(*element.vector_int);
159  case scheduler::UINT_TYPE: return fun(*element.vector_uint);
160  case scheduler::LONG_TYPE: return fun(*element.vector_long);
161  case scheduler::ULONG_TYPE: return fun(*element.vector_ulong);
162  case scheduler::FLOAT_TYPE : return fun(*element.vector_float);
163  case scheduler::DOUBLE_TYPE : return fun(*element.vector_double);
164  default : throw generator_not_supported_exception("Unsupported Scalartype");
165  }
166 }
167 
168 template<class Fun>
169 static typename Fun::result_type call_on_implicit_vector(scheduler::lhs_rhs_element element, Fun const & fun){
170  assert(element.type_family == scheduler::VECTOR_TYPE_FAMILY && bool("Must be called on a implicit_vector"));
171  assert(element.subtype == scheduler::IMPLICIT_VECTOR_TYPE && bool("Must be called on a implicit_vector"));
172  switch (element.numeric_type)
173  {
174  //case scheduler::CHAR_TYPE: return fun(*element.implicit_vector_char);
175  //case scheduler::UCHAR_TYPE: return fun(*element.implicit_vector_uchar);
176  //case scheduler::SHORT_TYPE: return fun(*element.implicit_vector_short);
177  //case scheduler::USHORT_TYPE: return fun(*element.implicit_vector_ushort);
178  case scheduler::INT_TYPE: return fun(*element.implicit_vector_int);
179  case scheduler::UINT_TYPE: return fun(*element.implicit_vector_uint);
180  case scheduler::LONG_TYPE: return fun(*element.implicit_vector_long);
181  case scheduler::ULONG_TYPE: return fun(*element.implicit_vector_ulong);
182  case scheduler::FLOAT_TYPE : return fun(*element.implicit_vector_float);
183  case scheduler::DOUBLE_TYPE : return fun(*element.implicit_vector_double);
184  default : throw generator_not_supported_exception("Unsupported Scalartype");
185  }
186 }
187 
188 template<class Fun>
189 static typename Fun::result_type call_on_matrix(scheduler::lhs_rhs_element element, Fun const & fun){
190  assert(element.type_family == scheduler::MATRIX_TYPE_FAMILY && bool("Must be called on a matrix"));
191  switch (element.numeric_type)
192  {
193  //case scheduler::CHAR_TYPE: return fun(*element.matrix_char);
194  //case scheduler::UCHAR_TYPE: return fun(*element.matrix_uchar);
195  //case scheduler::SHORT_TYPE: return fun(*element.matrix_short);
196  //case scheduler::USHORT_TYPE: return fun(*element.matrix_ushort);
197  case scheduler::INT_TYPE: return fun(*element.matrix_int);
198  case scheduler::UINT_TYPE: return fun(*element.matrix_uint);
199  case scheduler::LONG_TYPE: return fun(*element.matrix_long);
200  case scheduler::ULONG_TYPE: return fun(*element.matrix_ulong);
201  case scheduler::FLOAT_TYPE : return fun(*element.matrix_float);
202  case scheduler::DOUBLE_TYPE : return fun(*element.matrix_double);
203  default : throw generator_not_supported_exception("Unsupported Scalartype");
204  }
205 }
206 
207 
208 template<class Fun>
209 static typename Fun::result_type call_on_implicit_matrix(scheduler::lhs_rhs_element element, Fun const & fun){
210  assert(element.subtype == scheduler::IMPLICIT_MATRIX_TYPE && bool("Must be called on a implicit matrix"));
211  switch (element.numeric_type)
212  {
213  //case scheduler::CHAR_TYPE: return fun(*element.implicit_matrix_char);
214  //case scheduler::UCHAR_TYPE: return fun(*element.implicit_matrix_uchar);
215  //case scheduler::SHORT_TYPE: return fun(*element.implicit_matrix_short);
216  //case scheduler::USHORT_TYPE: return fun(*element.implicit_matrix_ushort);
217  case scheduler::INT_TYPE: return fun(*element.implicit_matrix_int);
218  case scheduler::UINT_TYPE: return fun(*element.implicit_matrix_uint);
219  case scheduler::LONG_TYPE: return fun(*element.implicit_matrix_long);
220  case scheduler::ULONG_TYPE: return fun(*element.implicit_matrix_ulong);
221  case scheduler::FLOAT_TYPE : return fun(*element.implicit_matrix_float);
222  case scheduler::DOUBLE_TYPE : return fun(*element.implicit_matrix_double);
223  default : throw generator_not_supported_exception("Unsupported Scalartype");
224  }
225 }
226 
227 template<class Fun>
228 static typename Fun::result_type call_on_element(scheduler::lhs_rhs_element const & element, Fun const & fun){
229  switch (element.type_family)
230  {
232  if (element.subtype == scheduler::HOST_SCALAR_TYPE)
233  return call_on_host_scalar(element, fun);
234  else
235  return call_on_scalar(element, fun);
237  if (element.subtype == scheduler::IMPLICIT_VECTOR_TYPE)
238  return call_on_implicit_vector(element, fun);
239  else
240  return call_on_vector(element, fun);
242  if (element.subtype == scheduler::IMPLICIT_MATRIX_TYPE)
243  return call_on_implicit_matrix(element, fun);
244  else
245  return call_on_matrix(element,fun);
246  default:
247  throw generator_not_supported_exception("Unsupported datastructure type : Not among {Scalar, Vector, Matrix}");
248  }
249 }
250 
252 {
254  result_type operator()(float const &) const { return sizeof(float); }
255  result_type operator()(double const &) const { return sizeof(double); }
256  template<class T> result_type operator()(T const &) const { return sizeof(typename viennacl::result_of::cpu_value_type<T>::type); }
257 };
258 
260 {
262  template<class T> result_type operator()(T const &t) const { return viennacl::traits::internal_size(t); }
263 };
264 
265 struct size_fun
266 {
268  template<class T> result_type operator()(T const &t) const { return viennacl::traits::size(t); }
269 };
270 
272 {
274  template<class T> result_type operator()(T const &t) const { return viennacl::traits::stride(t); }
275 };
276 
278 {
280  template<class T> result_type operator()(T const &t) const { return viennacl::traits::start1(t); }
281 };
282 
284 {
286  template<class T> result_type operator()(T const &t) const { return viennacl::traits::start2(t); }
287 };
288 
290 {
292  template<class T> result_type operator()(T const &t) const { return viennacl::traits::row_major(t)?viennacl::traits::stride2(t):viennacl::traits::stride1(t); }
293 };
294 
296 {
298  template<class T> result_type operator()(T const &t) const { return viennacl::traits::row_major(t)?viennacl::traits::start2(t):viennacl::traits::start1(t); }
299 };
300 
302 {
304  template<class T> result_type operator()(T const &t) const { return viennacl::traits::stride1(t); }
305 };
306 
308 {
310  template<class T> result_type operator()(T const &t) const { return viennacl::traits::stride2(t); }
311 };
312 
314 {
315  typedef cl_mem result_type;
316  template<class T>
317  result_type operator()(T const &t) const { return viennacl::traits::opencl_handle(t); }
318 };
319 
321 {
323  template<class T>
324  result_type operator()(T const &t) const { return viennacl::traits::internal_size1(t); }
325 };
326 
328 {
329  typedef bool result_type;
330  template<class T>
331  result_type operator()(T const &t) const { return viennacl::traits::row_major(t); }
332 };
333 
335 {
337  template<class T>
338  result_type operator()(T const &t) const { return viennacl::traits::internal_size2(t); }
339 };
340 
341 struct size1_fun
342 {
344  template<class T>
345  result_type operator()(T const &t) const { return viennacl::traits::size1(t); }
346 };
347 
348 struct size2_fun
349 {
351  template<class T>
352  result_type operator()(T const &t) const { return viennacl::traits::size2(t); }
353 };
354 
355 template<class T, class U>
356 struct is_same_type { enum { value = 0 }; };
357 
358 template<class T>
359 struct is_same_type<T,T> { enum { value = 1 }; };
360 
361 inline bool is_reduction(scheduler::statement_node const & node)
362 {
368 }
369 
371 {
376 }
377 template<class T>
379 template<> struct type_to_string<unsigned char> { static const char * value() { return "uchar"; } };
380 template<> struct type_to_string<char> { static const char * value() { return "char"; } };
381 template<> struct type_to_string<unsigned short> { static const char * value() { return "ushort"; } };
382 template<> struct type_to_string<short> { static const char * value() { return "short"; } };
383 template<> struct type_to_string<unsigned int> { static const char * value() { return "uint"; } };
384 template<> struct type_to_string<int> { static const char * value() { return "int"; } };
385 template<> struct type_to_string<unsigned long> { static const char * value() { return "ulong"; } };
386 template<> struct type_to_string<long> { static const char * value() { return "long"; } };
387 template<> struct type_to_string<float> { static const char * value() { return "float"; } };
388 template<> struct type_to_string<double> { static const char * value() { return "double"; } };
389 
390 
391 template<class T>
393 template<> struct first_letter_of_type<char> { static char value() { return 'c'; } };
394 template<> struct first_letter_of_type<unsigned char> { static char value() { return 'd'; } };
395 template<> struct first_letter_of_type<short> { static char value() { return 's'; } };
396 template<> struct first_letter_of_type<unsigned short> { static char value() { return 't'; } };
397 template<> struct first_letter_of_type<int> { static char value() { return 'i'; } };
398 template<> struct first_letter_of_type<unsigned int> { static char value() { return 'j'; } };
399 template<> struct first_letter_of_type<long> { static char value() { return 'l'; } };
400 template<> struct first_letter_of_type<unsigned long> { static char value() { return 'm'; } };
401 template<> struct first_letter_of_type<float> { static char value() { return 'f'; } };
402 template<> struct first_letter_of_type<double> { static char value() { return 'd'; } };
403 
404 class kernel_generation_stream : public std::ostream
405 {
406  class kgenstream : public std::stringbuf
407  {
408  public:
409  kgenstream(std::ostringstream& osstream,unsigned int const & tab_count) : oss_(osstream), tab_count_(tab_count){ }
410  int sync() {
411  for (unsigned int i=0; i<tab_count_;++i)
412  oss_ << " ";
413  oss_ << str();
414  str("");
415  return !oss_;
416  }
417 #if defined(_MSC_VER)
418  ~kgenstream() throw() { pubsync(); }
419 #else
420  ~kgenstream() { pubsync(); }
421 #endif
422  private:
423  std::ostream& oss_;
424  unsigned int const & tab_count_;
425  };
426 
427 public:
428  kernel_generation_stream() : std::ostream(new kgenstream(oss,tab_count_)), tab_count_(0){ }
429 #if defined(_MSC_VER)
430  ~kernel_generation_stream() throw() { delete rdbuf(); }
431 #else
432  ~kernel_generation_stream(){ delete rdbuf(); }
433 #endif
434 
435  std::string str(){ return oss.str(); }
436  void inc_tab(){ ++tab_count_; }
437  void dec_tab(){ --tab_count_; }
438 private:
439  unsigned int tab_count_;
440  std::ostringstream oss;
441 };
442 
443 inline bool node_leaf(scheduler::op_element const & op)
444 {
445  using namespace scheduler;
460 }
461 
463 {
464  using namespace scheduler;
474 }
475 
477 {
478  using namespace scheduler;
479  return
480 
492 
510 
522 
523 }
524 
526 {
527  using namespace tree_parsing;
528  assert(leaf==LHS_NODE_TYPE || leaf==RHS_NODE_TYPE);
529  if (leaf==LHS_NODE_TYPE)
530  return const_cast<scheduler::lhs_rhs_element &>(st.array()[idx].lhs);
531  return const_cast<scheduler::lhs_rhs_element &>(st.array()[idx].rhs);
532 }
533 
535 {
536  using namespace scheduler;
537  switch (type)
538  {
539  case UCHAR_TYPE:
540  case CHAR_TYPE: return 1;
541 
542  case USHORT_TYPE:
543  case SHORT_TYPE:
544  case HALF_TYPE: return 2;
545 
546  case UINT_TYPE:
547  case INT_TYPE:
548  case FLOAT_TYPE: return 4;
549 
550  case ULONG_TYPE:
551  case LONG_TYPE:
552  case DOUBLE_TYPE: return 8;
553 
554  default: throw generator_not_supported_exception("Unsupported scalartype");
555  }
556 }
557 
558 inline std::string append_width(std::string const & str, unsigned int width)
559 {
560  if (width==1)
561  return str;
562  return str + tools::to_string(width);
563 }
564 
565 }
566 }
567 }
568 #endif
result_type operator()(T const &t) const
Definition: utils.hpp:331
This file provides the forward declarations for the OpenCL layer of ViennaCL.
result_of::size_type< matrix_base< NumericT > >::type stride1(matrix_base< NumericT > const &s)
Definition: stride.hpp:55
Exception for the case the generator is unable to deal with the operation.
Definition: forwards.h:163
Generic size and resize functionality for different vector and matrix types.
result_type operator()(T const &t) const
Definition: utils.hpp:324
result_type operator()(T const &t) const
Definition: utils.hpp:345
Various little tools used here and there in ViennaCL.
vcl_size_t internal_size1(matrix_base< NumericT > const &mat)
Helper routine for obtaining the internal number of entries per row of a ViennaCL matrix...
Definition: size.hpp:382
result_type operator()(T const &t) const
Definition: utils.hpp:280
result_type operator()(T const &t) const
Definition: utils.hpp:352
vcl_size_t size1(MatrixType const &mat)
Generic routine for obtaining the number of rows of a matrix (ViennaCL, uBLAS, etc.)
Definition: size.hpp:163
vcl_size_t internal_size2(matrix_base< NumericT > const &mat)
Helper routine for obtaining the internal number of entries per column of a ViennaCL matrix...
Definition: size.hpp:390
bool elementwise_operator(scheduler::op_element const &op)
Definition: utils.hpp:462
result_type operator()(T const &t) const
Definition: utils.hpp:304
result_of::size_type< viennacl::vector_base< T > >::type stride(viennacl::vector_base< T > const &s)
Definition: stride.hpp:45
result_of::size_type< T >::type start1(T const &obj)
Definition: start.hpp:65
A class representing the 'data' for the LHS or RHS operand of the respective node.
Definition: forwards.h:337
container_type const & array() const
Definition: forwards.h:528
vcl_size_t internal_size(vector_base< NumericT > const &vec)
Helper routine for obtaining the buffer length of a ViennaCL vector.
Definition: size.hpp:371
statement_node_numeric_type
Encodes the type of a node in the statement tree.
Definition: forwards.h:286
bool node_leaf(scheduler::op_element const &op)
Definition: utils.hpp:443
Forward declaration of dense matrix classes.
std::string opencl_source_to_cuda_source(std::string const &opencl_src)
Definition: utils.hpp:50
operation_node_type_family type_family
Definition: forwards.h:473
Struct for holding the type family as well as the type of an operation (could be addition, subtraction, norm, etc.)
Definition: forwards.h:471
result_of::size_type< MatrixType >::type size2(MatrixType const &mat)
Generic routine for obtaining the number of columns of a matrix (ViennaCL, uBLAS, etc...
Definition: size.hpp:201
result_type operator()(float const &) const
Definition: utils.hpp:254
result_type operator()(T const &t) const
Definition: utils.hpp:262
Main namespace in ViennaCL. Holds all the basic types such as vector, matrix, etc. and defines operations upon them.
Definition: cpu_ram.hpp:34
vcl_size_t size(VectorType const &vec)
Generic routine for obtaining the size of a vector (ViennaCL, uBLAS, etc.)
Definition: size.hpp:235
result_of::size_type< T >::type start2(T const &obj)
Definition: start.hpp:84
bool elementwise_function(scheduler::op_element const &op)
Definition: utils.hpp:476
int find_and_replace(std::string &source, std::string const &find, std::string const &replace)
Replace in a source string a pattern by another.
Definition: tools.hpp:160
result_type operator()(T const &) const
Definition: utils.hpp:256
result_type operator()(double const &) const
Definition: utils.hpp:255
result_type operator()(T const &t) const
Definition: utils.hpp:286
bool is_reduction(scheduler::statement_node const &node)
Definition: utils.hpp:361
Forwards declaration.
Determines whether a given expression has a row-major matrix layout.
std::size_t vcl_size_t
Definition: forwards.h:75
result_type operator()(T const &t) const
Definition: utils.hpp:292
Provides the datastructures for dealing with a single statement such as 'x = y + z;'.
T::ERROR_CANNOT_DEDUCE_CPU_SCALAR_TYPE_FOR_T type
Definition: result_of.hpp:271
result_of::size_type< matrix_base< NumericT > >::type stride2(matrix_base< NumericT > const &s)
Definition: stride.hpp:65
result_type operator()(T const &t) const
Definition: utils.hpp:298
scheduler::lhs_rhs_element & lhs_rhs_element(scheduler::statement const &st, vcl_size_t idx, leaf_t leaf)
Definition: utils.hpp:525
bool row_major(T const &)
Definition: row_major.hpp:38
operation_node_type type
Definition: forwards.h:474
bool is_index_reduction(scheduler::op_element const &op)
Definition: utils.hpp:370
The main class for representing a statement such as x = inner_prod(y,z); at runtime.
Definition: forwards.h:502
Forward declarations of the implicit_vector_base, vector_base class.
result_type operator()(T const &t) const
Definition: utils.hpp:338
Extracts the underlying OpenCL handle from a vector, a matrix, an expression etc. ...
result_type operator()(T const &t) const
Definition: utils.hpp:268
std::string to_string(T const t)
Definition: tools.hpp:304
result_type operator()(T const &t) const
Definition: utils.hpp:310
Main datastructure for an node in the statement tree.
Definition: forwards.h:478
unsigned int size_of(scheduler::statement_node_numeric_type type)
Definition: utils.hpp:534
result_type operator()(T const &t) const
Definition: utils.hpp:317
result_type operator()(T const &t) const
Definition: utils.hpp:274
std::string append_width(std::string const &str, unsigned int width)
Definition: utils.hpp:558