about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBronek Kozicki <brok@spamcop.net>2017-10-01T12·14+0100
committerBronek Kozicki <brok@spamcop.net>2017-10-06T18·59+0100
commit89f1f531d373f5e4eab77960d3b0e8c05d879c7c (patch)
tree1db2881a0f49c61ec56a2e95eb21327c2d444b07
parent962e9931d546cd6f062894e15283cea02c7d3220 (diff)
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
-rw-r--r--absl/types/any.h50
1 files changed, 29 insertions, 21 deletions
diff --git a/absl/types/any.h b/absl/types/any.h
index a51dea110d0f..fe104818898e 100644
--- a/absl/types/any.h
+++ b/absl/types/any.h
@@ -94,23 +94,20 @@ namespace absl {
 
 namespace any_internal {
 
-// FastTypeId<Type>() evaluates at compile/link-time to a unique integer for the
-// passed in type. Their values are neither contiguous nor small, making them
-// unfit for using as an index into a vector, but a good match for keys into
-// 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>
+struct TypeTag {
+  constexpr static char dummy_var = 0;
+};
+
+template <typename Type>
+constexpr char TypeTag<Type>::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>
-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
-  // no concurrency issues.
-  static char dummy_var;
-  return reinterpret_cast<size_t>(&dummy_var);
+constexpr inline const void* FastTypeId() {
+  return &TypeTag<Type>::dummy_var;
 }
 
 }  // namespace any_internal
@@ -382,10 +379,20 @@ class any {
    public:
     virtual ~ObjInterface() = default;
     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
     virtual const std::type_info& Type() const noexcept = 0;
 #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.
@@ -400,7 +407,7 @@ class any {
       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
     const std::type_info& Type() const noexcept final { return typeid(T); }
@@ -415,7 +422,7 @@ class any {
   }
 
   template <typename T>
-  static size_t IdForType() {
+  constexpr static const void* IdForType() {
     // Note: This type dance is to make the behavior consistent with typeid.
     using NormalizedType =
         typename std::remove_cv<typename std::remove_reference<T>::type>::type;
@@ -423,8 +430,9 @@ class any {
     return any_internal::FastTypeId<NormalizedType>();
   }
 
-  size_t GetObjTypeId() const {
-    return obj_ == nullptr ? any_internal::FastTypeId<void>() : obj_->type_id();
+  const void* GetObjTypeId() const {
+    return obj_ == nullptr ? any_internal::FastTypeId<void>()
+                           : obj_->ObjTypeId();
   }
 
   // `absl::any` nonmember functions //