Skip to content
Snippets Groups Projects
Commit 89f1f531 authored by Bronek Kozicki's avatar Bronek Kozicki
Browse files

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
parent 962e9931
No related branches found
No related tags found
No related merge requests found
...@@ -94,23 +94,20 @@ namespace absl { ...@@ -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 template <typename Type>
// 32-bit integer. While a client should never do that it SHOULD still be safe, constexpr char TypeTag<Type>::dummy_var;
// assuming the BSS segment doesn't span more than 4GiB.
// 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> template<typename Type>
inline size_t FastTypeId() { constexpr inline const void* FastTypeId() {
static_assert(sizeof(char*) <= sizeof(size_t), return &TypeTag<Type>::dummy_var;
"ptr size too large for size_t");
// This static variable isn't actually used, only its address, so there are
// no concurrency issues.
static char dummy_var;
return reinterpret_cast<size_t>(&dummy_var);
} }
} // namespace any_internal } // namespace any_internal
...@@ -382,10 +379,20 @@ class any { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 //
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment