1#pragma once
2
3#include <c10/util/C++17.h>
4#include <c10/util/ConstexprCrc.h>
5#include <c10/util/IdWrapper.h>
6#include <c10/util/string_view.h>
7#include <cinttypes>
8#include <functional>
9
10namespace c10 {
11namespace util {
12
13// TODO Make it work for more compilers
14
15// Intel compiler works
16#if defined(__INTEL_COMPILER)
17#define C10_TYPENAME_SUPPORTS_CONSTEXPR 0
18#define C10_TYPENAME_CONSTEXPR
19
20// Clang works
21#elif defined(__clang__)
22
23// except for NVCC
24#if defined(__CUDACC__)
25#define C10_TYPENAME_SUPPORTS_CONSTEXPR 0
26#define C10_TYPENAME_CONSTEXPR
27#else
28#define C10_TYPENAME_SUPPORTS_CONSTEXPR 1
29#define C10_TYPENAME_CONSTEXPR constexpr
30#endif
31
32// Windows works
33#elif defined(_MSC_VER)
34
35// except for NVCC
36#if defined(__CUDACC__)
37#define C10_TYPENAME_SUPPORTS_CONSTEXPR 0
38#define C10_TYPENAME_CONSTEXPR
39#else
40#define C10_TYPENAME_SUPPORTS_CONSTEXPR 1
41#define C10_TYPENAME_CONSTEXPR constexpr
42#endif
43
44// GCC works
45#elif defined(__GNUC__)
46
47// except when gcc < 9
48#if (__GNUC__ < 9) || defined(__CUDACC__)
49#define C10_TYPENAME_SUPPORTS_CONSTEXPR 0
50#define C10_TYPENAME_CONSTEXPR
51#else
52#define C10_TYPENAME_SUPPORTS_CONSTEXPR 1
53#define C10_TYPENAME_CONSTEXPR constexpr
54#endif
55
56// some other compiler we don't know about
57#else
58#define C10_TYPENAME_SUPPORTS_CONSTEXPR 1
59#define C10_TYPENAME_CONSTEXPR constexpr
60#endif
61
62struct type_index final : IdWrapper<type_index, uint64_t> {
63 constexpr explicit type_index(uint64_t checksum) : IdWrapper(checksum) {}
64
65 // Allow usage in std::map / std::set
66 // TODO Disallow this and rather use std::unordered_map/set everywhere
67 friend constexpr bool operator<(type_index lhs, type_index rhs) noexcept {
68 return lhs.underlyingId() < rhs.underlyingId();
69 }
70
71 friend std::ostream& operator<<(std::ostream& stream, type_index typeId) {
72 return stream << typeId.underlyingId();
73 }
74};
75
76namespace detail {
77
78#if !defined(__clang__) && !defined(_MSC_VER) && defined(__GNUC__) && \
79 __GNUC__ < 5
80// Getting __PRETTY_FUNCTION__ at compile time only works with GCC >= 5
81#error "You're running a too old version of GCC. We need GCC 5 or later."
82#endif
83
84#if defined(__clang__) && __clang_major__ < 4
85// Getting __PRETTY_FUNCTION__ at compile time only works with Clang >= 4
86#error "You're running a too old version of Clang. We need Clang 4 or later."
87#endif
88
89inline constexpr string_view extract(
90 string_view prefix,
91 string_view suffix,
92 string_view str) {
93#if !defined(__CUDA_ARCH__) // CUDA doesn't like std::logic_error in device code
94 return (!str.starts_with(prefix) || !str.ends_with(suffix))
95 ? (throw std::logic_error("Invalid pattern"), string_view())
96 : str.substr(prefix.size(), str.size() - prefix.size() - suffix.size());
97#else
98 return str.substr(prefix.size(), str.size() - prefix.size() - suffix.size());
99#endif
100}
101
102template <typename T>
103inline C10_TYPENAME_CONSTEXPR c10::string_view fully_qualified_type_name_impl() {
104#if defined(_MSC_VER) && !defined(__clang__)
105#if defined(__NVCC__)
106 return extract(
107 "c10::basic_string_view<char> c10::util::detail::fully_qualified_type_name_impl<",
108 ">()",
109 __FUNCSIG__);
110#else
111 return extract(
112 "class c10::basic_string_view<char> __cdecl c10::util::detail::fully_qualified_type_name_impl<",
113 ">(void)",
114 __FUNCSIG__);
115#endif
116#elif defined(__clang__)
117 return extract(
118 "c10::string_view c10::util::detail::fully_qualified_type_name_impl() [T = ",
119 "]",
120 __PRETTY_FUNCTION__);
121#elif defined(__GNUC__)
122 return extract(
123#if C10_TYPENAME_SUPPORTS_CONSTEXPR
124 "constexpr c10::string_view c10::util::detail::fully_qualified_type_name_impl() [with T = ",
125#else
126 "c10::string_view c10::util::detail::fully_qualified_type_name_impl() [with T = ",
127#endif
128 "; c10::string_view = c10::basic_string_view<char>]",
129 __PRETTY_FUNCTION__);
130#endif
131}
132
133#if !defined(__CUDA_ARCH__)
134template <typename T>
135inline constexpr uint64_t type_index_impl() {
136// Idea: __PRETTY_FUNCTION__ (or __FUNCSIG__ on msvc) contains a qualified name
137// of this function, including its template parameter, i.e. including the
138// type we want an id for. We use this name and run crc64 on it to get a type
139// id.
140#if defined(_MSC_VER) && !defined(__clang__)
141 return crc64(__FUNCSIG__, sizeof(__FUNCSIG__)).checksum();
142#elif defined(__clang__)
143 return crc64(__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__)).checksum();
144#elif defined(__GNUC__)
145 return crc64(__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__)).checksum();
146#endif
147}
148#endif
149
150} // namespace detail
151
152template <typename T>
153inline constexpr type_index get_type_index() {
154#if !defined(__CUDA_ARCH__)
155 // To enforce that this is really computed at compile time, we pass the
156 // type index through std::integral_constant.
157 return type_index{std::integral_constant<
158 uint64_t,
159 detail::type_index_impl<std::decay_t<T>>()>::value};
160#else
161 // There's nothing in theory preventing us from running this on device code
162 // except for nvcc throwing a compiler error if we enable it.
163 return (abort(), type_index(0));
164#endif
165}
166
167#if !defined(TORCH_PEDANTIC)
168// Use precomputed hashsum for std::string
169// Needed to workaround ambiguity in class name resolution
170// into __PRETTY_FUNCION__ when abovementioned class is defined in inlined
171// namespace. In multi-ABI C++ library, `std::string` is an alias to
172// `std::__cxx11::basic_string<char>` which depending on compiler flags can be
173// resolved to `basic_string<char>` either in `std` namespace or in
174// `std::__cxx11` one (`__cxx11` is an inline namespace)
175template <>
176inline constexpr type_index get_type_index<std::string>() {
177 // hashsum for std::basic_string<char>
178 return type_index{4193213214807308375ULL};
179}
180#endif
181
182template <typename T>
183inline C10_TYPENAME_CONSTEXPR string_view
184get_fully_qualified_type_name() noexcept {
185#if C10_TYPENAME_SUPPORTS_CONSTEXPR
186 constexpr
187#else
188 static
189#endif
190 string_view name = detail::fully_qualified_type_name_impl<T>();
191 return name;
192}
193} // namespace util
194} // namespace c10
195
196C10_DEFINE_HASH_FOR_IDWRAPPER(c10::util::type_index);
197