|
| 1 | +//===--- __clang_interpreter_runtime_printvalue.h ---*- C++ |
| 2 | +//-*-===// |
| 3 | +// |
| 4 | +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 5 | +// See https://llvm.org/LICENSE.txt for license information. |
| 6 | +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 7 | +// |
| 8 | +//===----------------------------------------------------------------------===// |
| 9 | +// |
| 10 | +// This file defines runtime functions used to print STL components in |
| 11 | +// clang-repl. They are very heavy so we should only include it once and on |
| 12 | +// demand. |
| 13 | +// |
| 14 | +//===----------------------------------------------------------------------===// |
| 15 | +#ifndef LLVM_CLANG_INTERPRETER_RUNTIME_PRINT_VALUE_H |
| 16 | +#define LLVM_CLANG_INTERPRETER_RUNTIME_PRINT_VALUE_H |
| 17 | + |
| 18 | +#if !defined(__CLANG_REPL__) |
| 19 | +#error "This file should only be included by clang-repl!" |
| 20 | +#endif |
| 21 | + |
| 22 | +namespace caas { |
| 23 | +namespace runtime {} |
| 24 | +} // namespace caas |
| 25 | +using namespace caas::runtime; |
| 26 | + |
| 27 | +#include <memory> |
| 28 | +#include <string> |
| 29 | +#include <tuple> |
| 30 | +#include <type_traits> |
| 31 | +#include <vector> |
| 32 | + |
| 33 | +// FIXME: We should include it somewhere instead of duplicating it... |
| 34 | +#if __has_attribute(visibility) && \ |
| 35 | + (!(defined(_WIN32) || defined(__CYGWIN__)) || \ |
| 36 | + (defined(__MINGW32__) && defined(__clang__))) |
| 37 | +#if defined(LLVM_BUILD_LLVM_DYLIB) || defined(LLVM_BUILD_SHARED_LIBS) |
| 38 | +#define __REPL_EXTERNAL_VISIBILITY __attribute__((visibility("default"))) |
| 39 | +#else |
| 40 | +#define __REPL_EXTERNAL_VISIBILITY |
| 41 | +#endif |
| 42 | +#else |
| 43 | +#if defined(_WIN32) |
| 44 | +#define __REPL_EXTERNAL_VISIBILITY __declspec(dllexport) |
| 45 | +#endif |
| 46 | +#endif |
| 47 | + |
| 48 | +// Fallback. |
| 49 | +template <class T, |
| 50 | + typename std::enable_if<!std::is_pointer<T>::value>::type * = nullptr> |
| 51 | +inline std::string PrintValueRuntime(const T &) { |
| 52 | + return "{not representable}"; |
| 53 | +} |
| 54 | + |
| 55 | +// Forward declare the pre-compiled printing functions. |
| 56 | +#ifndef __DECL_PRINT_VALUE_RUNTIME |
| 57 | +#define __DECL_PRINT_VALUE_RUNTIME(type) \ |
| 58 | + __REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const type *__Ptr) |
| 59 | +__DECL_PRINT_VALUE_RUNTIME(void); // |
| 60 | +__DECL_PRINT_VALUE_RUNTIME(void *); // |
| 61 | +__DECL_PRINT_VALUE_RUNTIME(char *const); // |
| 62 | +__DECL_PRINT_VALUE_RUNTIME(char *); // |
| 63 | +__DECL_PRINT_VALUE_RUNTIME(bool); |
| 64 | +__DECL_PRINT_VALUE_RUNTIME(char); |
| 65 | +__DECL_PRINT_VALUE_RUNTIME(signed char); |
| 66 | +__DECL_PRINT_VALUE_RUNTIME(short); |
| 67 | +__DECL_PRINT_VALUE_RUNTIME(unsigned short); |
| 68 | +__DECL_PRINT_VALUE_RUNTIME(int); |
| 69 | +__DECL_PRINT_VALUE_RUNTIME(unsigned int); |
| 70 | +__DECL_PRINT_VALUE_RUNTIME(long); |
| 71 | +__DECL_PRINT_VALUE_RUNTIME(unsigned long); |
| 72 | +__DECL_PRINT_VALUE_RUNTIME(long long); |
| 73 | +__DECL_PRINT_VALUE_RUNTIME(unsigned long long); |
| 74 | +__DECL_PRINT_VALUE_RUNTIME(float); |
| 75 | +__DECL_PRINT_VALUE_RUNTIME(double); |
| 76 | +__DECL_PRINT_VALUE_RUNTIME(long double); |
| 77 | +#endif |
| 78 | + |
| 79 | +namespace __repl_runtime_detail { |
| 80 | + |
| 81 | +// Custom void_t implementation for C++11 compatibility |
| 82 | +template <typename... Ts> struct __repl_void_impl { |
| 83 | + typedef void type; |
| 84 | +}; |
| 85 | + |
| 86 | +// Helper to deduce the type of the expression 'std::begin(std::declval<T &>())' |
| 87 | +template <typename T> |
| 88 | +using __repl_begin_result = decltype(std::begin(std::declval<T &>())); |
| 89 | + |
| 90 | +// Helper to deduce the type of the expression 'std::end(std::declval<T &>())' |
| 91 | +template <typename T> |
| 92 | +using __repl_end_result = decltype(std::end(std::declval<T &>())); |
| 93 | + |
| 94 | +// Type trait to check if a type is iterable |
| 95 | +template <typename T, typename = void> |
| 96 | +struct __is_iterable : std::false_type {}; |
| 97 | + |
| 98 | +template <typename T> |
| 99 | +struct __is_iterable<T, typename __repl_void_impl<__repl_begin_result<T>, |
| 100 | + __repl_end_result<T>>::type> |
| 101 | + : std::true_type {}; |
| 102 | + |
| 103 | +// Type trait to check if a type is std::pair |
| 104 | +template <typename T> struct __is_pair : std::false_type {}; |
| 105 | + |
| 106 | +template <typename T, typename U> |
| 107 | +struct __is_pair<std::pair<T, U>> : std::true_type {}; |
| 108 | + |
| 109 | +// Type trait to check if a type is std::map (or any associative container with |
| 110 | +// mapped_type) |
| 111 | +template <typename T, typename = void> struct __is_map : std::false_type {}; |
| 112 | + |
| 113 | +template <typename T> |
| 114 | +struct __is_map<T, typename __repl_void_impl<typename T::mapped_type>::type> |
| 115 | + : std::true_type {}; |
| 116 | + |
| 117 | +// The type of the elements is std::pair, and the container is a map like type. |
| 118 | +template < |
| 119 | + typename Container, typename Elt, |
| 120 | + typename std::enable_if<__is_pair<Elt>::value && __is_map<Container>::value, |
| 121 | + bool>::type = true> |
| 122 | +std::string __PrintCollectionElt(const Elt &Val) { |
| 123 | + return PrintValueRuntime(&Val.first) + " => " + |
| 124 | + PrintValueRuntime(&Val.second); |
| 125 | +} |
| 126 | + |
| 127 | +// The type of the elements is std::pair, and the container isn't a map-like |
| 128 | +// type. |
| 129 | +template <typename Container, typename Elt, |
| 130 | + typename std::enable_if<__is_pair<Elt>::value && |
| 131 | + !__is_map<Container>::value, |
| 132 | + bool>::type = true> |
| 133 | +std::string __PrintCollectionElt(const Elt &Val) { |
| 134 | + return TuplePairPrintValue(&Val); |
| 135 | +} |
| 136 | + |
| 137 | +template <typename Container, typename Elt, |
| 138 | + typename std::enable_if<!__is_pair<Elt>::value, bool>::type = true> |
| 139 | +std::string __PrintCollectionElt(const Elt &Val) { |
| 140 | + return PrintValueRuntime(&Val); |
| 141 | +} |
| 142 | + |
| 143 | +template <class Tuple, std::size_t N = std::tuple_size<Tuple>(), |
| 144 | + std::size_t TupleSize = std::tuple_size<Tuple>()> |
| 145 | +struct __TupleLikePrinter { |
| 146 | + static std::string print(const Tuple *T) { |
| 147 | + constexpr std::size_t EltNum = TupleSize - N; |
| 148 | + std::string Str; |
| 149 | + // Not the first element. |
| 150 | + if (EltNum != 0) |
| 151 | + Str += ", "; |
| 152 | + Str += PrintValueRuntime(&std::get<EltNum>(*T)); |
| 153 | + // If N+1 is not smaller than the size of the tuple, |
| 154 | + // reroute the call to the printing function to the |
| 155 | + // no-op specialisation to stop recursion. |
| 156 | + constexpr std::size_t Nm1 = N - 1; |
| 157 | + Str += __TupleLikePrinter<Tuple, Nm1>::print((const Tuple *)T); |
| 158 | + return Str; |
| 159 | + } |
| 160 | +}; |
| 161 | + |
| 162 | +template <class Tuple, std::size_t TupleSize> |
| 163 | +struct __TupleLikePrinter<Tuple, 0, TupleSize> { |
| 164 | + static std::string print(const Tuple *T) { return ""; } |
| 165 | +}; |
| 166 | + |
| 167 | +template <class T> inline std::string TuplePairPrintValue(const T *Val) { |
| 168 | + std::string Str("{ "); |
| 169 | + Str += __TupleLikePrinter<T>::print(Val); |
| 170 | + Str += " }"; |
| 171 | + return Str; |
| 172 | +} |
| 173 | + |
| 174 | +struct __StdVectorBool { |
| 175 | + bool Value; |
| 176 | + __StdVectorBool(bool V) : Value(V) {} |
| 177 | +}; |
| 178 | +template <typename T> |
| 179 | +std::string __PrintCollectionElt(const __StdVectorBool &Val) { |
| 180 | + return PrintValueRuntime(&Val.Value); |
| 181 | +} |
| 182 | + |
| 183 | +} // namespace __repl_runtime_detail |
| 184 | + |
| 185 | +template <typename Container, |
| 186 | + typename std::enable_if< |
| 187 | + __repl_runtime_detail::__is_iterable<Container>::value, |
| 188 | + bool>::type = true> |
| 189 | +inline std::string PrintValueRuntime(const Container *C) { |
| 190 | + std::string Str("{ "); |
| 191 | + |
| 192 | + for (auto Beg = C->begin(), End = C->end(); Beg != End; Beg++) { |
| 193 | + if (Beg != C->begin()) |
| 194 | + Str += ", "; |
| 195 | + Str += __repl_runtime_detail::__PrintCollectionElt<Container>(*Beg); |
| 196 | + } |
| 197 | + Str += " }"; |
| 198 | + return Str; |
| 199 | +} |
| 200 | + |
| 201 | +template <typename T, size_t N> |
| 202 | +inline std::string PrintValueRuntime(const T (*Obj)[N]) { |
| 203 | + if (N == 0) |
| 204 | + return "{}"; |
| 205 | + |
| 206 | + std::string Str = "{ "; |
| 207 | + for (size_t Idx = 0; Idx < N; ++Idx) { |
| 208 | + Str += PrintValueRuntime(*Obj + Idx); |
| 209 | + if (Idx < N - 1) |
| 210 | + Str += ", "; |
| 211 | + } |
| 212 | + return Str + " }"; |
| 213 | +} |
| 214 | + |
| 215 | +template <size_t N> inline std::string PrintValueRuntime(const char (*Obj)[N]) { |
| 216 | + const auto *Str = reinterpret_cast<const char *const>(Obj); |
| 217 | + return PrintValueRuntime(&Str); |
| 218 | +} |
| 219 | + |
| 220 | +// std::vector<bool> |
| 221 | +inline std::string PrintValueRuntime(const std::vector<bool> *Val) { |
| 222 | + // Try our best to fix std::vector<bool> without too much of templated code. |
| 223 | + std::vector<__repl_runtime_detail::__StdVectorBool> ValFixed(Val->begin(), |
| 224 | + Val->end()); |
| 225 | + return PrintValueRuntime<decltype(ValFixed)>(&ValFixed); |
| 226 | +} |
| 227 | + |
| 228 | +// tuple |
| 229 | +template <typename... Ts> |
| 230 | +inline std::string PrintValueRuntime(const std::tuple<Ts...> *Val) { |
| 231 | + using T = std::tuple<Ts...>; |
| 232 | + return __repl_runtime_detail::TuplePairPrintValue<T>(Val); |
| 233 | +} |
| 234 | + |
| 235 | +// pair |
| 236 | +template <typename... Ts> |
| 237 | +inline std::string PrintValueRuntime(const std::pair<Ts...> *Val) { |
| 238 | + using T = std::pair<Ts...>; |
| 239 | + return __repl_runtime_detail::TuplePairPrintValue<T>(Val); |
| 240 | +} |
| 241 | + |
| 242 | +// unique_ptr |
| 243 | +template <class T> |
| 244 | +inline std::string PrintValueRuntime(const std::unique_ptr<T> *Val) { |
| 245 | + auto Ptr = Val->get(); |
| 246 | + return "std::unique_ptr -> " + PrintValueRuntime((const void **)&Ptr); |
| 247 | +} |
| 248 | + |
| 249 | +// shared_ptr |
| 250 | +template <class T> |
| 251 | +inline std::string PrintValueRuntime(const std::shared_ptr<T> *Val) { |
| 252 | + auto Ptr = Val->get(); |
| 253 | + return "std::shared_ptr -> " + PrintValueRuntime((const void **)&Ptr); |
| 254 | +} |
| 255 | + |
| 256 | +// weak_ptr |
| 257 | +template <class T> |
| 258 | +inline std::string PrintValueRuntime(const std::weak_ptr<T> *Val) { |
| 259 | + auto Ptr = Val->lock().get(); |
| 260 | + return "std::weak_ptr -> " + PrintValueRuntime((const void **)&Ptr); |
| 261 | +} |
| 262 | + |
| 263 | +// string |
| 264 | +template <class T> |
| 265 | +inline std::string PrintValueRuntime(const std::basic_string<T> *Val) { |
| 266 | + const char *Chars = Val->c_str(); |
| 267 | + return PrintValueRuntime((const char **)&Chars); |
| 268 | +} |
| 269 | +#endif |
0 commit comments