1 // The MIT License (MIT)
2 
3 // Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
4 
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of
6 // this software and associated documentation files (the "Software"), to deal in
7 // the Software without restriction, including without limitation the rights to
8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 // the Software, and to permit persons to whom the Software is furnished to do so,
10 // subject to the following conditions:
11 
12 // The above copyright notice and this permission notice shall be included in all
13 // copies or substantial portions of the Software.
14 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22 #ifndef SOL_DEMANGLE_HPP
23 #define SOL_DEMANGLE_HPP
24 
25 #include <string>
26 #include <array>
27 #include <cctype>
28 
29 namespace sol {
30 	namespace detail {
31 #ifdef _MSC_VER
32 		template <typename T>
ctti_get_type_name()33 		inline std::string ctti_get_type_name() {
34 			const static std::array<std::string, 7> removals = { { "public:", "private:", "protected:", "struct ", "class ", "`anonymous-namespace'", "`anonymous namespace'" } };
35 			std::string name = __FUNCSIG__;
36 			std::size_t start = name.find("get_type_name");
37 			if (start == std::string::npos)
38 				start = 0;
39 			else
40 				start += 13;
41 			if (start < name.size() - 1)
42 				start += 1;
43 			std::size_t end = name.find_last_of('>');
44 			if (end == std::string::npos)
45 				end = name.size();
46 			name = name.substr(start, end - start);
47 			if (name.find("struct", 0) == 0)
48 				name.replace(0, 6, "", 0);
49 			if (name.find("class", 0) == 0)
50 				name.replace(0, 5, "", 0);
51 			while (!name.empty() && std::isblank(name.front())) name.erase(name.begin());
52 			while (!name.empty() && std::isblank(name.back())) name.pop_back();
53 
54 			for (std::size_t r = 0; r < removals.size(); ++r) {
55 				auto found = name.find(removals[r]);
56 				while (found != std::string::npos) {
57 					name.erase(found, removals[r].size());
58 					found = name.find(removals[r]);
59 				}
60 			}
61 
62 			return name;
63 		}
64 #elif defined(__GNUC__) || defined(__clang__)
65 		template <typename T, class seperator_mark = int>
66 		inline std::string ctti_get_type_name() {
67 			const static std::array<std::string, 2> removals = { { "{anonymous}", "(anonymous namespace)" } };
68 			std::string name = __PRETTY_FUNCTION__;
69 			std::size_t start = name.find_first_of('[');
70 			start = name.find_first_of('=', start);
71 			std::size_t end = name.find_last_of(']');
72 			if (end == std::string::npos)
73 				end = name.size();
74 			if (start == std::string::npos)
75 				start = 0;
76 			if (start < name.size() - 1)
77 				start += 1;
78 			name = name.substr(start, end - start);
79 			start = name.rfind("seperator_mark");
80 			if (start != std::string::npos) {
81 				name.erase(start - 2, name.length());
82 			}
83 			while (!name.empty() && std::isblank(name.front())) name.erase(name.begin());
84 			while (!name.empty() && std::isblank(name.back())) name.pop_back();
85 
86 			for (std::size_t r = 0; r < removals.size(); ++r) {
87 				auto found = name.find(removals[r]);
88 				while (found != std::string::npos) {
89 					name.erase(found, removals[r].size());
90 					found = name.find(removals[r]);
91 				}
92 			}
93 
94 			return name;
95 		}
96 #else
97 #error Compiler not supported for demangling
98 #endif // compilers
99 
100 		template <typename T>
demangle_once()101 		inline std::string demangle_once() {
102 			std::string realname = ctti_get_type_name<T>();
103 			return realname;
104 		}
105 
106 		template <typename T>
short_demangle_once()107 		inline std::string short_demangle_once() {
108 			std::string realname = ctti_get_type_name<T>();
109 			// This isn't the most complete but it'll do for now...?
110 			static const std::array<std::string, 10> ops = { { "operator<", "operator<<", "operator<<=", "operator<=", "operator>", "operator>>", "operator>>=", "operator>=", "operator->", "operator->*" } };
111 			int level = 0;
112 			std::ptrdiff_t idx = 0;
113 			for (idx = static_cast<std::ptrdiff_t>(realname.empty() ? 0 : realname.size() - 1); idx > 0; --idx) {
114 				if (level == 0 && realname[idx] == ':') {
115 					break;
116 				}
117 				bool isleft = realname[idx] == '<';
118 				bool isright = realname[idx] == '>';
119 				if (!isleft && !isright)
120 					continue;
121 				bool earlybreak = false;
122 				for (const auto& op : ops) {
123 					std::size_t nisop = realname.rfind(op, idx);
124 					if (nisop == std::string::npos)
125 						continue;
126 					std::size_t nisopidx = idx - op.size() + 1;
127 					if (nisop == nisopidx) {
128 						idx = static_cast<std::ptrdiff_t>(nisopidx);
129 						earlybreak = true;
130 					}
131 					break;
132 				}
133 				if (earlybreak) {
134 					continue;
135 				}
136 				level += isleft ? -1 : 1;
137 			}
138 			if (idx > 0) {
139 				realname.erase(0, realname.length() < static_cast<std::size_t>(idx) ? realname.length() : idx + 1);
140 			}
141 			return realname;
142 		}
143 
144 		template <typename T>
demangle()145 		inline const std::string& demangle() {
146 			static const std::string d = demangle_once<T>();
147 			return d;
148 		}
149 
150 		template <typename T>
short_demangle()151 		inline const std::string& short_demangle() {
152 			static const std::string d = short_demangle_once<T>();
153 			return d;
154 		}
155 	} // detail
156 } // sol
157 
158 #endif // SOL_DEMANGLE_HPP
159