• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 Google Inc. All rights reserved.
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 #ifndef FRUIT_TYPE_INFO_DEFN_H
18 #define FRUIT_TYPE_INFO_DEFN_H
19 
20 #include <fruit/impl/util/type_info.h>
21 
22 #include <fruit/fruit_forward_decls.h>
23 #include <fruit/impl/data_structures/arena_allocator.h>
24 #include <fruit/impl/data_structures/memory_pool.h>
25 #include <fruit/impl/fruit-config.h>
26 #include <fruit/impl/fruit_assert.h>
27 
28 namespace fruit {
29 namespace impl {
30 
31 template <typename T, bool is_abstract = std::is_abstract<T>::value>
32 struct GetConcreteTypeInfo {
operatorGetConcreteTypeInfo33   constexpr TypeInfo::ConcreteTypeInfo operator()() const {
34     return TypeInfo::ConcreteTypeInfo{
35         sizeof(T), alignof(T), std::is_trivially_destructible<T>::value,
36 #if FRUIT_EXTRA_DEBUG
37         false /* is_abstract */,
38 #endif
39     };
40   }
41 };
42 
43 // For abstract types we don't need the real information.
44 // Also, some compilers might report compile errors in this case, for example alignof(T) doesn't work in Visual Studio
45 // when T is an abstract type.
46 template <typename T>
47 struct GetConcreteTypeInfo<T, true> {
48   constexpr TypeInfo::ConcreteTypeInfo operator()() const {
49     return TypeInfo::ConcreteTypeInfo{
50         0 /* type_size */, 0 /* type_alignment */, false /* is_trivially_destructible */,
51 #if FRUIT_EXTRA_DEBUG
52         true /* is_abstract */,
53 #endif
54     };
55   }
56 };
57 
58 // This should only be used if RTTI is disabled. Use the other constructor if possible.
59 inline constexpr TypeInfo::TypeInfo(ConcreteTypeInfo concrete_type_info)
60     : info(nullptr), concrete_type_info(concrete_type_info) {}
61 
62 inline constexpr TypeInfo::TypeInfo(const std::type_info& info, ConcreteTypeInfo concrete_type_info)
63     : info(&info), concrete_type_info(concrete_type_info) {}
64 
65 inline std::string TypeInfo::name() const {
66   if (info != nullptr) // LCOV_EXCL_BR_LINE
67     return demangleTypeName(info->name());
68   else
69     return "<unknown> (type name not accessible because RTTI is disabled)"; // LCOV_EXCL_LINE
70 }
71 
72 inline size_t TypeInfo::size() const {
73 #if FRUIT_EXTRA_DEBUG
74   FruitAssert(!concrete_type_info.is_abstract);
75 #endif
76   return concrete_type_info.type_size;
77 }
78 
79 inline size_t TypeInfo::alignment() const {
80 #if FRUIT_EXTRA_DEBUG
81   FruitAssert(!concrete_type_info.is_abstract);
82 #endif
83   return concrete_type_info.type_alignment;
84 }
85 
86 inline bool TypeInfo::isTriviallyDestructible() const {
87 #if FRUIT_EXTRA_DEBUG
88   FruitAssert(!concrete_type_info.is_abstract);
89 #endif
90   return concrete_type_info.is_trivially_destructible;
91 }
92 
93 inline TypeId::operator std::string() const {
94   return type_info->name();
95 }
96 
97 inline bool TypeId::operator==(TypeId x) const {
98   return type_info == x.type_info;
99 }
100 
101 inline bool TypeId::operator!=(TypeId x) const {
102   return type_info != x.type_info;
103 }
104 
105 inline bool TypeId::operator<(TypeId x) const {
106   return type_info < x.type_info;
107 }
108 
109 template <typename T>
110 struct GetTypeInfoForType {
111   constexpr TypeInfo operator()() const {
112 #if FRUIT_HAS_TYPEID
113     return TypeInfo(typeid(T), GetConcreteTypeInfo<T>()());
114 #else
115     return TypeInfo(GetConcreteTypeInfo<T>()());
116 #endif
117   };
118 };
119 
120 template <typename Annotation, typename T>
121 struct GetTypeInfoForType<fruit::Annotated<Annotation, T>> {
122   constexpr TypeInfo operator()() const {
123 #if FRUIT_HAS_TYPEID
124     return TypeInfo(typeid(fruit::Annotated<Annotation, T>), GetConcreteTypeInfo<T>()());
125 #else
126     return TypeInfo(GetConcreteTypeInfo<T>()());
127 #endif
128   };
129 };
130 
131 template <typename T>
132 inline TypeId getTypeId() {
133 #if FRUIT_HAS_TYPEID && !FRUIT_HAS_CONSTEXPR_TYPEID
134   // We can't use constexpr here because TypeInfo contains a `const std::type_info&` and that's not constexpr with the
135   // current compiler/STL.
136   static TypeInfo info = GetTypeInfoForType<T>()();
137 #else
138   // Usual case. The `constexpr' ensures compile-time evaluation.
139   static constexpr TypeInfo info = GetTypeInfoForType<T>()();
140 #endif
141   return TypeId{&info};
142 }
143 
144 template <typename L>
145 struct GetTypeIdsForListHelper;
146 
147 template <typename... Ts>
148 struct GetTypeIdsForListHelper<fruit::impl::meta::Vector<Ts...>> {
149   std::vector<TypeId, ArenaAllocator<TypeId>> operator()(MemoryPool& memory_pool) {
150     return std::vector<TypeId, ArenaAllocator<TypeId>>(std::initializer_list<TypeId>{getTypeId<Ts>()...}, memory_pool);
151   }
152 };
153 
154 template <typename L>
155 std::vector<TypeId, ArenaAllocator<TypeId>> getTypeIdsForList(MemoryPool& memory_pool) {
156   return GetTypeIdsForListHelper<L>()(memory_pool);
157 }
158 
159 #if FRUIT_EXTRA_DEBUG
160 
161 inline std::ostream& operator<<(std::ostream& os, TypeId type) {
162   return os << std::string(type);
163 }
164 
165 #endif // FRUIT_EXTRA_DEBUG
166 
167 } // namespace impl
168 } // namespace fruit
169 
170 namespace std {
171 
172 inline std::size_t hash<fruit::impl::TypeId>::operator()(fruit::impl::TypeId type) const {
173   return hash<const fruit::impl::TypeInfo*>()(type.type_info);
174 }
175 
176 } // namespace std
177 
178 #endif // FRUIT_TYPE_INFO_DEFN_H
179