Make any_internal::FastTypeId() and IdForType() constexpr
This means removing all side effects from FastTypeId(). So rather than instantiate dummy_var in the first call to FastTypeId(), move this responsibility to the linker, and only read its address during execution - guaranteed to never change. This allows for more optimization opportunities, with more explicit uses of constexpr
This commit is contained in:
		
							parent
							
								
									962e9931d5
								
							
						
					
					
						commit
						89f1f531d3
					
				
					 1 changed files with 29 additions and 21 deletions
				
			
		|  | @ -94,23 +94,20 @@ namespace absl { | ||||||
| 
 | 
 | ||||||
| namespace any_internal { | namespace any_internal { | ||||||
| 
 | 
 | ||||||
| // FastTypeId<Type>() evaluates at compile/link-time to a unique integer for the
 | template <typename Type> | ||||||
| // passed in type. Their values are neither contiguous nor small, making them
 | struct TypeTag { | ||||||
| // unfit for using as an index into a vector, but a good match for keys into
 |   constexpr static char dummy_var = 0; | ||||||
| // maps or straight up comparisons.
 | }; | ||||||
| // Note that on 64-bit (unix) systems size_t is 64-bit while int is 32-bit and
 |  | ||||||
| // the compiler will happily and quietly assign such a 64-bit value to a
 |  | ||||||
| // 32-bit integer. While a client should never do that it SHOULD still be safe,
 |  | ||||||
| // assuming the BSS segment doesn't span more than 4GiB.
 |  | ||||||
| template<typename Type> |  | ||||||
| inline size_t FastTypeId() { |  | ||||||
|   static_assert(sizeof(char*) <= sizeof(size_t), |  | ||||||
|                 "ptr size too large for size_t"); |  | ||||||
| 
 | 
 | ||||||
|   // This static variable isn't actually used, only its address, so there are
 | template <typename Type> | ||||||
|   // no concurrency issues.
 | constexpr char TypeTag<Type>::dummy_var; | ||||||
|   static char dummy_var; | 
 | ||||||
|   return reinterpret_cast<size_t>(&dummy_var); | // FastTypeId<Type>() evaluates at compile/link-time to a unique pointer for the
 | ||||||
|  | // passed in type. These are meant to be good match for keys into maps or straight
 | ||||||
|  | // up comparisons.
 | ||||||
|  | template<typename Type> | ||||||
|  | constexpr inline const void* FastTypeId() { | ||||||
|  |   return &TypeTag<Type>::dummy_var; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| }  // namespace any_internal
 | }  // namespace any_internal
 | ||||||
|  | @ -382,10 +379,20 @@ class any { | ||||||
|    public: |    public: | ||||||
|     virtual ~ObjInterface() = default; |     virtual ~ObjInterface() = default; | ||||||
|     virtual std::unique_ptr<ObjInterface> Clone() const = 0; |     virtual std::unique_ptr<ObjInterface> Clone() const = 0; | ||||||
|     virtual size_t type_id() const noexcept = 0; |     virtual const void* ObjTypeId() const noexcept = 0; | ||||||
| #if ABSL_ANY_DETAIL_HAS_RTTI | #if ABSL_ANY_DETAIL_HAS_RTTI | ||||||
|     virtual const std::type_info& Type() const noexcept = 0; |     virtual const std::type_info& Type() const noexcept = 0; | ||||||
| #endif  // ABSL_ANY_DETAIL_HAS_RTTI
 | #endif  // ABSL_ANY_DETAIL_HAS_RTTI
 | ||||||
|  | 
 | ||||||
|  |     // Note that on 64-bit (unix) systems size_t is 64-bit while int is 32-bit and
 | ||||||
|  |     // the compiler will happily and quietly assign such a 64-bit value to a
 | ||||||
|  |     // 32-bit integer. While a client should never do that it SHOULD still be safe,
 | ||||||
|  |     // assuming the BSS segment doesn't span more than 4GiB.
 | ||||||
|  |     size_t type_id() const noexcept { | ||||||
|  |       static_assert(sizeof(void*) <= sizeof(size_t), | ||||||
|  |                     "ptr size too large for size_t"); | ||||||
|  |       return reinterpret_cast<size_t>(ObjTypeId()); | ||||||
|  |     } | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   // Hold a value of some queryable type, with an ability to Clone it.
 |   // Hold a value of some queryable type, with an ability to Clone it.
 | ||||||
|  | @ -400,7 +407,7 @@ class any { | ||||||
|       return std::unique_ptr<ObjInterface>(new Obj(in_place, value)); |       return std::unique_ptr<ObjInterface>(new Obj(in_place, value)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     size_t type_id() const noexcept final { return IdForType<T>(); } |     const void* ObjTypeId() const noexcept final { return IdForType<T>(); } | ||||||
| 
 | 
 | ||||||
| #if ABSL_ANY_DETAIL_HAS_RTTI | #if ABSL_ANY_DETAIL_HAS_RTTI | ||||||
|     const std::type_info& Type() const noexcept final { return typeid(T); } |     const std::type_info& Type() const noexcept final { return typeid(T); } | ||||||
|  | @ -415,7 +422,7 @@ class any { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   template <typename T> |   template <typename T> | ||||||
|   static size_t IdForType() { |   constexpr static const void* IdForType() { | ||||||
|     // Note: This type dance is to make the behavior consistent with typeid.
 |     // Note: This type dance is to make the behavior consistent with typeid.
 | ||||||
|     using NormalizedType = |     using NormalizedType = | ||||||
|         typename std::remove_cv<typename std::remove_reference<T>::type>::type; |         typename std::remove_cv<typename std::remove_reference<T>::type>::type; | ||||||
|  | @ -423,8 +430,9 @@ class any { | ||||||
|     return any_internal::FastTypeId<NormalizedType>(); |     return any_internal::FastTypeId<NormalizedType>(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   size_t GetObjTypeId() const { |   const void* GetObjTypeId() const { | ||||||
|     return obj_ == nullptr ? any_internal::FastTypeId<void>() : obj_->type_id(); |     return obj_ == nullptr ? any_internal::FastTypeId<void>() | ||||||
|  |                            : obj_->ObjTypeId(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // `absl::any` nonmember functions //
 |   // `absl::any` nonmember functions //
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue