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