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