OmniSciDB  c1a53651b2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
toString.h
Go to the documentation of this file.
1 /*
2  * Copyright 2022 HEAVY.AI, 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 /*
18  This header file provides the following C++ template functions:
19 
20  toString(const T& v) -> std::string
21 
22  Convert object v of type T to string. Pretty-printing is
23  enabled for objects that types define `toString` or `to_string`
24  methods.
25 
26  typeName(const T* v) -> std::string
27 
28  Return the type name of an object passed in via its pointer
29  value.
30 
31  and a convenience macro `PRINT(EXPR)` that sends the string
32  representation of any expression to stdout.
33 */
34 
35 #pragma once
36 
37 #ifndef __CUDACC__
38 
39 #define HAVE_TOSTRING
40 
41 #ifndef _WIN32
42 #include <cxxabi.h>
43 #endif
44 
45 #include <cassert>
46 #include <chrono>
47 #include <iostream>
48 #include <list>
49 #include <map>
50 #include <set>
51 #include <sstream>
52 #include <tuple>
53 #include <type_traits>
54 #include <unordered_map>
55 #include <unordered_set>
56 #include <vector>
57 #include "sqldefs.h"
58 
59 #ifdef ENABLE_TOSTRING_RAPIDJSON
60 #if __has_include(<rapidjson/document.h> )
61 #include <rapidjson/document.h>
62 #include <rapidjson/stringbuffer.h>
63 #include <rapidjson/writer.h>
64 #else
65 #undefine ENABLE_TOSTRING_RAPIDJSON
66 #endif
67 #endif
68 
69 #ifdef ENABLE_TOSTRING_LLVM
70 #if __has_include(<llvm/Support/raw_os_ostream.h> )
71 #include <llvm/IR/Value.h>
72 #include <llvm/Support/raw_os_ostream.h>
73 #include "clang/Driver/Job.h"
74 #include "llvm/IR/Function.h"
75 #include "llvm/IR/Module.h"
76 #include "llvm/Option/ArgList.h"
77 #else
78 #undefine ENABLE_TOSTRING_LLVM
79 #endif
80 #endif
81 
82 #ifdef ENABLE_TOSTRING_PTHREAD
83 #include <pthread.h>
84 
85 #endif
86 
87 #include <mutex>
88 inline static std::mutex toString_PRINT_mutex;
89 
90 #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
91 #define PRINT(...) \
92  { \
93  std::lock_guard<std::mutex> print_lock(toString_PRINT_mutex); \
94  std::cout << std::hex \
95  << ((std::hash<std::thread::id>()(std::this_thread::get_id())) & 0xffff) \
96  << std::dec << " [" << __FILENAME__ << ":" << __func__ << "#" << __LINE__ \
97  << "]: " #__VA_ARGS__ "=" << ::toString(std::make_tuple(__VA_ARGS__)) \
98  << std::endl \
99  << std::flush; \
100  }
101 
102 template <typename T>
103 std::string typeName(const T* v) {
104  std::stringstream stream;
105  int status;
106 #ifdef _WIN32
107  stream << std::string(typeid(T).name());
108 #else
109  char* demangled = abi::__cxa_demangle(typeid(T).name(), 0, 0, &status);
110  stream << std::string(demangled);
111  free(demangled);
112 #endif
113  return stream.str();
114 }
115 
116 template <typename T, typename... Args>
117 std::string typeName(T (*v)(Args... args)) {
118  std::stringstream stream;
119  int status;
120 #ifdef _WIN32
121  stream << std::string(typeid(v).name());
122 #else
123  char* demangled = abi::__cxa_demangle(typeid(v).name(), 0, 0, &status);
124  stream << std::string(demangled);
125  free(demangled);
126 #endif
127  stream << "@0x" << std::hex << (uintptr_t)(reinterpret_cast<const void*>(v));
128  return stream.str();
129 }
130 
131 namespace {
132 
133 template <typename T, typename = void>
134 struct has_toString : std::false_type {};
135 template <typename T>
136 struct has_toString<T, decltype(std::declval<T>().toString(), void())> : std::true_type {
137 };
138 template <class T>
139 inline constexpr bool has_toString_v = has_toString<T>::value;
140 
141 template <typename T, typename = void>
142 struct get_has_toString : std::false_type {};
143 template <typename T>
144 struct get_has_toString<T, decltype(std::declval<T>().get()->toString(), void())>
145  : std::true_type {};
146 template <class T>
148 
149 #ifdef ENABLE_TOSTRING_to_string
150 template <typename T, typename = void>
151 struct has_to_string : std::false_type {};
152 template <typename T>
153 struct has_to_string<T, decltype(std::declval<T>().to_string(), void())>
154  : std::true_type {};
155 template <class T>
156 inline constexpr bool has_to_string_v = has_to_string<T>::value;
157 #endif
158 
159 #ifdef ENABLE_TOSTRING_str
160 template <typename T, typename = void>
161 struct has_str : std::false_type {};
162 template <typename T>
163 struct has_str<T, decltype(std::declval<T>().str(), void())> : std::true_type {};
164 template <class T>
165 inline constexpr bool has_str_v = has_str<T>::value;
166 #endif
167 
168 template <typename T, typename = void>
169 struct has_printTo : std::false_type {};
170 template <typename T>
171 struct has_printTo<T,
172  decltype(std::declval<T>().printTo(std::declval<std::ostream&>()),
173  void())> : std::true_type {};
174 template <class T>
175 inline constexpr bool has_printTo_v = has_printTo<T>::value;
176 
177 } // namespace
178 
179 template <typename T>
180 std::string toString(const T& v) {
181  if constexpr (std::is_same_v<T, std::string>) { // NOLINT
182  return "\"" + v + "\"";
183 #ifdef ENABLE_TOSTRING_RAPIDJSON
184  } else if constexpr (std::is_same_v<T, rapidjson::Value>) { // NOLINT
185  rapidjson::StringBuffer buffer;
186  rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
187  v.Accept(writer);
188  return buffer.GetString();
189 #endif
190 #ifdef ENABLE_TOSTRING_LLVM
191  } else if constexpr (std::is_same_v<T, llvm::Module>) { // NOLINT
192  std::string type_str;
193  llvm::raw_string_ostream rso(type_str);
194  v.print(rso, nullptr);
195  return "(" + rso.str() + ")";
196  } else if constexpr (std::is_same_v<T, llvm::Function>) { // NOLINT
197  std::string type_str;
198  llvm::raw_string_ostream rso(type_str);
199  v.print(rso, nullptr);
200  return "(" + rso.str() + ")";
201  } else if constexpr (std::is_same_v<T, llvm::Value>) { // NOLINT
202  std::string type_str;
203  llvm::raw_string_ostream rso(type_str);
204  v.print(rso);
205  return "(" + rso.str() + ")";
206  } else if constexpr (std::is_same_v<T, llvm::Argument>) { // NOLINT
207  std::string type_str;
208  llvm::raw_string_ostream rso(type_str);
209  v.print(rso);
210  return "(" + rso.str() + ")";
211  } else if constexpr (std::is_same_v<T, llvm::Type>) { // NOLINT
212  std::string type_str;
213  llvm::raw_string_ostream rso(type_str);
214  v.print(rso);
215  return "(" + rso.str() + ")";
216  } else if constexpr (std::is_same_v<T, llvm::Triple>) { // NOLINT
217  return v.str();
218  } else if constexpr (std::is_same_v<T, llvm::opt::ArgStringList>) { // NOLINT
219  std::string r;
220  for (unsigned i = 0; i < v.size(); i++) {
221  if (i) {
222  r += ", ";
223  }
224  r += v[i];
225  }
226  return "[" + r + "]";
227  } else if constexpr (std::is_same_v<T, llvm::opt::DerivedArgList>) { // NOLINT
228  std::string r;
229  for (unsigned i = 0; i < v.getNumInputArgStrings(); i++) {
230  if (i) {
231  r += ", ";
232  }
233  r += v.getArgString(i);
234  }
235  return "[" + r + "]";
236  } else if constexpr (std::is_same_v<T, clang::driver::JobList>) { // NOLINT
237  std::string type_str;
238  llvm::raw_string_ostream rso(type_str);
239  v.Print(rso, nullptr, true);
240  return rso.str();
241 #endif
242 #ifdef ENABLE_TOSTRING_PTHREAD
243  } else if constexpr (std::is_same_v<T, pthread_mutex_t>) { // NOLINT
244  std::string r;
245  r += "lock=" + std::to_string(v.__data.__lock);
246  r += ", &owner=" + std::to_string(v.__data.__owner);
247  r += ", &nusers=" + std::to_string(v.__data.__nusers);
248  r += ", &count=" + std::to_string(v.__data.__count);
249  return "{" + r + "}";
250 #endif
251  } else if constexpr (std::is_same_v<T, bool>) { // NOLINT
252  return v ? "True" : "False";
253  } else if constexpr (std::is_arithmetic_v<T>) { // NOLINT
254  return std::to_string(v);
255 #ifdef ENABLE_TOSTRING_str
256  } else if constexpr (has_str_v<T>) { // NOLINT
257  return v.str();
258 #endif
259 #ifdef ENABLE_TOSTRING_to_string
260  } else if constexpr (has_to_string_v<T>) { // NOLINT
261  return v.to_string();
262 #endif
263  } else if constexpr (has_toString_v<T>) { // NOLINT
264  return v.toString();
265  } else if constexpr (get_has_toString_v<T>) {
266  auto ptr = v.get();
267  return (ptr == NULL ? "NULL" : "&" + ptr->toString());
268  } else if constexpr (std::is_same_v<T, void*>) {
269  std::ostringstream ss;
270  ss << std::hex << (uintptr_t)v;
271  return "0x" + ss.str();
272  } else if constexpr (std::is_same_v<
273  T,
274  std::chrono::time_point<std::chrono::system_clock>>) {
275  std::string s(30, '\0');
276  auto converted_v = (std::chrono::time_point<std::chrono::system_clock>)v;
277  std::time_t ts = std::chrono::system_clock::to_time_t(v);
278  std::strftime(&s[0], s.size(), "%Y-%m-%d %H:%M:%S", std::localtime(&ts));
279  return s + "." +
280  std::to_string((converted_v.time_since_epoch().count() / 1000) % 1000000);
281  } else if constexpr (std::is_same_v<T, JoinType>) {
282  switch (v) {
283  case JoinType::INNER:
284  return "INNER";
285  case JoinType::LEFT:
286  return "LEFT";
287  case JoinType::SEMI:
288  return "SEMI";
289  case JoinType::ANTI:
290  return "ANTI";
292  return "WINDOW_FUNCTION";
294  return "WINDOW_FUNCTION_FRAMING";
295  case JoinType::INVALID:
296  return "INVALID";
297  }
298  assert(false);
299  return "";
300  } else if constexpr (std::is_pointer_v<T>) {
301  return (v == NULL ? "NULL" : "&" + toString(*v));
302  } else if constexpr (has_printTo_v<T>) {
303  std::ostringstream ss;
304  v.printTo(ss);
305  return ss.str();
306  } else {
307  return typeName(&v);
308  }
309 }
310 
311 #ifdef ENABLE_TOSTRING_PTHREAD
312 template <typename T>
313 std::string toString(T& v) {
314  if constexpr (std::is_same_v<T, std::mutex>) { // NOLINT
315  auto p = v.native_handle();
316  return "mutex" + toString(*p);
317  } else {
318  const T* w = &v;
319  return toString(*w);
320  }
321 }
322 #endif
323 
324 template <typename T1, typename T2>
325 std::string toString(const std::pair<T1, T2>& v) {
326  return "(" + toString(v.first) + ", " + toString(v.second) + ")";
327 }
328 
329 template <typename T>
330 std::string toString(const std::vector<T>& v) {
331  auto result = std::string("[");
332  for (size_t i = 0; i < v.size(); ++i) {
333  if (i) {
334  result += ", ";
335  }
336  result += toString(v[i]);
337  }
338  result += "]";
339  return result;
340 }
341 
342 template <typename T1, typename T2>
343 std::string toString(const std::unordered_map<T1, T2>& v) {
344  auto result = std::string("{");
345  size_t i = 0;
346  for (const auto& p : v) {
347  if (i) {
348  result += ", ";
349  }
350  result += toString(p);
351  i++;
352  }
353  result += "}";
354  return result;
355 }
356 
357 template <typename T1, typename T2>
358 std::string toString(const std::map<T1, T2>& v) {
359  auto result = std::string("{");
360  size_t i = 0;
361  for (const auto& p : v) {
362  if (i) {
363  result += ", ";
364  }
365  result += toString(p);
366  i++;
367  }
368  result += "}";
369  return result;
370 }
371 
372 template <typename T>
373 std::string toString(const std::list<T>& v) {
374  auto result = std::string("[");
375  size_t i = 0;
376  for (const auto& p : v) {
377  if (i) {
378  result += ", ";
379  }
380  result += toString(p);
381  i++;
382  }
383  result += "]";
384  return result;
385 }
386 
387 template <typename T>
388 std::string toString(const std::unordered_set<T>& v) {
389  auto result = std::string("{");
390  size_t i = 0;
391  for (const auto& p : v) {
392  if (i) {
393  result += ", ";
394  }
395  result += toString(p);
396  i++;
397  }
398  result += "}";
399  return result;
400 }
401 
402 template <typename T>
403 std::string toString(const std::set<T>& v) {
404  auto result = std::string("{");
405  size_t i = 0;
406  for (const auto& p : v) {
407  if (i) {
408  result += ", ";
409  }
410  result += toString(p);
411  i++;
412  }
413  result += "}";
414  return result;
415 }
416 
417 template <typename... Ts, size_t... Is>
418 std::string toStringImpl(const std::tuple<Ts...>& t,
419  const std::index_sequence<0, Is...>) {
420  return (toString(std::get<0>(t)) + ... + (", " + toString(std::get<Is>(t))));
421 }
422 
423 template <typename... T>
424 std::string toStringImpl(const std::tuple<>& t, const std::index_sequence<>) {
425  return {};
426 }
427 
428 template <typename... Ts>
429 std::string toString(const std::tuple<Ts...>& t) {
430  return "(" + toStringImpl(t, std::index_sequence_for<Ts...>{}) + ")";
431 }
432 
433 #else
434 
435 #define PRINT(...)
436 
437 #endif // ifndef __CUDACC__
static std::mutex toString_PRINT_mutex
Definition: toString.h:88
constexpr bool has_toString_v
Definition: toString.h:139
std::string to_string(char const *&&v)
std::string toStringImpl(const std::tuple< Ts...> &t, const std::index_sequence< 0, Is...>)
Definition: toString.h:418
struct get_has_toString< T, decltype(std::declval< T >().get() -> void())> constexpr bool get_has_toString_v
Definition: toString.h:147
std::string toString(const ExecutorDeviceType &device_type)
std::string typeName(const T *v)
Definition: toString.h:103
constexpr bool has_printTo_v
Definition: toString.h:175
Common Enum definitions for SQL processing.
string name
Definition: setup.in.py:72