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