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…
Reference in a new issue