about summary refs log tree commit diff
path: root/absl/base
diff options
context:
space:
mode:
Diffstat (limited to 'absl/base')
-rw-r--r--absl/base/BUILD.bazel25
-rw-r--r--absl/base/CMakeLists.txt25
-rw-r--r--absl/base/internal/bits.h24
-rw-r--r--absl/base/internal/fast_type_id.h48
-rw-r--r--absl/base/internal/fast_type_id_test.cc123
5 files changed, 233 insertions, 12 deletions
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
index 24dab79102f0..1af9e45e668a 100644
--- a/absl/base/BUILD.bazel
+++ b/absl/base/BUILD.bazel
@@ -750,3 +750,28 @@ cc_binary(
         "@com_github_google_benchmark//:benchmark_main",
     ],
 )
+
+cc_library(
+    name = "fast_type_id",
+    hdrs = ["internal/fast_type_id.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = [
+        "//absl:__subpackages__",
+    ],
+    deps = [
+        ":config",
+    ],
+)
+
+cc_test(
+    name = "fast_type_id_test",
+    size = "small",
+    srcs = ["internal/fast_type_id_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":fast_type_id",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt
index 4230d2e73ee1..545499200247 100644
--- a/absl/base/CMakeLists.txt
+++ b/absl/base/CMakeLists.txt
@@ -674,3 +674,28 @@ absl_cc_test(
     gmock
     gtest_main
 )
+
+absl_cc_library(
+  NAME
+    fast_type_id
+  HDRS
+    "internal/fast_type_id.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  LINKOPTS
+    ${ABSL_DEFAULT_LINKOPTS}
+  DEPS
+    absl::config
+)
+
+absl_cc_test(
+  NAME
+    fast_type_id_test
+  SRCS
+    "internal/fast_type_id_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::fast_type_id
+    gtest_main
+)
diff --git a/absl/base/internal/bits.h b/absl/base/internal/bits.h
index 8b03453c184f..14c51d8b3013 100644
--- a/absl/base/internal/bits.h
+++ b/absl/base/internal/bits.h
@@ -24,7 +24,7 @@
 
 // Clang on Windows has __builtin_clzll; otherwise we need to use the
 // windows intrinsic functions.
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) && !defined(__clang__)
 #include <intrin.h>
 #if defined(_M_X64)
 #pragma intrinsic(_BitScanReverse64)
@@ -36,7 +36,7 @@
 
 #include "absl/base/attributes.h"
 
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) && !defined(__clang__)
 // We can achieve something similar to attribute((always_inline)) with MSVC by
 // using the __forceinline keyword, however this is not perfect. MSVC is
 // much less aggressive about inlining, and even with the __forceinline keyword.
@@ -73,14 +73,14 @@ ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64Slow(uint64_t n) {
 }
 
 ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) {
-#if defined(_MSC_VER) && defined(_M_X64)
+#if defined(_MSC_VER) && !defined(__clang__) && defined(_M_X64)
   // MSVC does not have __buitin_clzll. Use _BitScanReverse64.
   unsigned long result = 0;  // NOLINT(runtime/int)
   if (_BitScanReverse64(&result, n)) {
     return 63 - result;
   }
   return 64;
-#elif defined(_MSC_VER)
+#elif defined(_MSC_VER) && !defined(__clang__)
   // MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse
   unsigned long result = 0;  // NOLINT(runtime/int)
   if ((n >> 32) && _BitScanReverse(&result, n >> 32)) {
@@ -90,7 +90,7 @@ ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) {
     return 63 - result;
   }
   return 64;
-#elif defined(__GNUC__)
+#elif defined(__GNUC__) || defined(__clang__)
   // Use __builtin_clzll, which uses the following instructions:
   //  x86: bsr
   //  ARM64: clz
@@ -126,13 +126,13 @@ ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32Slow(uint64_t n) {
 }
 
 ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32(uint32_t n) {
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) && !defined(__clang__)
   unsigned long result = 0;  // NOLINT(runtime/int)
   if (_BitScanReverse(&result, n)) {
     return 31 - result;
   }
   return 32;
-#elif defined(__GNUC__)
+#elif defined(__GNUC__) || defined(__clang__)
   // Use __builtin_clz, which uses the following instructions:
   //  x86: bsr
   //  ARM64: clz
@@ -163,11 +163,11 @@ ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64Slow(uint64_t n) {
 }
 
 ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64(uint64_t n) {
-#if defined(_MSC_VER) && defined(_M_X64)
+#if defined(_MSC_VER) && !defined(__clang__) && defined(_M_X64)
   unsigned long result = 0;  // NOLINT(runtime/int)
   _BitScanForward64(&result, n);
   return result;
-#elif defined(_MSC_VER)
+#elif defined(_MSC_VER) && !defined(__clang__)
   unsigned long result = 0;  // NOLINT(runtime/int)
   if (static_cast<uint32_t>(n) == 0) {
     _BitScanForward(&result, n >> 32);
@@ -175,7 +175,7 @@ ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64(uint64_t n) {
   }
   _BitScanForward(&result, n);
   return result;
-#elif defined(__GNUC__)
+#elif defined(__GNUC__) || defined(__clang__)
   static_assert(sizeof(unsigned long long) == sizeof(n),  // NOLINT(runtime/int)
                 "__builtin_ctzll does not take 64-bit arg");
   return __builtin_ctzll(n);
@@ -196,11 +196,11 @@ ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32Slow(uint32_t n) {
 }
 
 ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32(uint32_t n) {
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) && !defined(__clang__)
   unsigned long result = 0;  // NOLINT(runtime/int)
   _BitScanForward(&result, n);
   return result;
-#elif defined(__GNUC__)
+#elif defined(__GNUC__) || defined(__clang__)
   static_assert(sizeof(int) == sizeof(n),
                 "__builtin_ctz does not take 32-bit arg");
   return __builtin_ctz(n);
diff --git a/absl/base/internal/fast_type_id.h b/absl/base/internal/fast_type_id.h
new file mode 100644
index 000000000000..3db59e83745b
--- /dev/null
+++ b/absl/base/internal/fast_type_id.h
@@ -0,0 +1,48 @@
+//
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
+#define ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+template <typename Type>
+struct FastTypeTag {
+  constexpr static char dummy_var = 0;
+};
+
+template <typename Type>
+constexpr char FastTypeTag<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.
+using FastTypeIdType = const void*;
+
+template <typename Type>
+constexpr inline FastTypeIdType FastTypeId() {
+  return &FastTypeTag<Type>::dummy_var;
+}
+
+}  // namespace base_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
diff --git a/absl/base/internal/fast_type_id_test.cc b/absl/base/internal/fast_type_id_test.cc
new file mode 100644
index 000000000000..16f3c1458bdf
--- /dev/null
+++ b/absl/base/internal/fast_type_id_test.cc
@@ -0,0 +1,123 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/fast_type_id.h"
+
+#include <cstdint>
+#include <map>
+#include <vector>
+
+#include "gtest/gtest.h"
+
+namespace {
+namespace bi = absl::base_internal;
+
+// NOLINTNEXTLINE
+#define PRIM_TYPES(A)   \
+  A(bool)               \
+  A(short)              \
+  A(unsigned short)     \
+  A(int)                \
+  A(unsigned int)       \
+  A(long)               \
+  A(unsigned long)      \
+  A(long long)          \
+  A(unsigned long long) \
+  A(float)              \
+  A(double)             \
+  A(long double)
+
+TEST(FastTypeIdTest, PrimitiveTypes) {
+  bi::FastTypeIdType type_ids[] = {
+#define A(T) bi::FastTypeId<T>(),
+    PRIM_TYPES(A)
+#undef A
+#define A(T) bi::FastTypeId<const T>(),
+    PRIM_TYPES(A)
+#undef A
+#define A(T) bi::FastTypeId<volatile T>(),
+    PRIM_TYPES(A)
+#undef A
+#define A(T) bi::FastTypeId<const volatile T>(),
+    PRIM_TYPES(A)
+#undef A
+  };
+  size_t total_type_ids = sizeof(type_ids) / sizeof(bi::FastTypeIdType);
+
+  for (int i = 0; i < total_type_ids; ++i) {
+    EXPECT_EQ(type_ids[i], type_ids[i]);
+    for (int j = 0; j < i; ++j) {
+      EXPECT_NE(type_ids[i], type_ids[j]);
+    }
+  }
+}
+
+#define FIXED_WIDTH_TYPES(A) \
+  A(int8_t)                  \
+  A(uint8_t)                 \
+  A(int16_t)                 \
+  A(uint16_t)                \
+  A(int32_t)                 \
+  A(uint32_t)                \
+  A(int64_t)                 \
+  A(uint64_t)
+
+TEST(FastTypeIdTest, FixedWidthTypes) {
+  bi::FastTypeIdType type_ids[] = {
+#define A(T) bi::FastTypeId<T>(),
+    FIXED_WIDTH_TYPES(A)
+#undef A
+#define A(T) bi::FastTypeId<const T>(),
+    FIXED_WIDTH_TYPES(A)
+#undef A
+#define A(T) bi::FastTypeId<volatile T>(),
+    FIXED_WIDTH_TYPES(A)
+#undef A
+#define A(T) bi::FastTypeId<const volatile T>(),
+    FIXED_WIDTH_TYPES(A)
+#undef A
+  };
+  size_t total_type_ids = sizeof(type_ids) / sizeof(bi::FastTypeIdType);
+
+  for (int i = 0; i < total_type_ids; ++i) {
+    EXPECT_EQ(type_ids[i], type_ids[i]);
+    for (int j = 0; j < i; ++j) {
+      EXPECT_NE(type_ids[i], type_ids[j]);
+    }
+  }
+}
+
+TEST(FastTypeIdTest, AliasTypes) {
+  using int_alias = int;
+  EXPECT_EQ(bi::FastTypeId<int_alias>(), bi::FastTypeId<int>());
+}
+
+TEST(FastTypeIdTest, TemplateSpecializations) {
+  EXPECT_NE(bi::FastTypeId<std::vector<int>>(),
+            bi::FastTypeId<std::vector<long>>());
+
+  EXPECT_NE((bi::FastTypeId<std::map<int, float>>()),
+            (bi::FastTypeId<std::map<int, double>>()));
+}
+
+struct Base {};
+struct Derived : Base {};
+struct PDerived : private Base {};
+
+TEST(FastTypeIdTest, Inheritance) {
+  EXPECT_NE(bi::FastTypeId<Base>(), bi::FastTypeId<Derived>());
+  EXPECT_NE(bi::FastTypeId<Base>(), bi::FastTypeId<PDerived>());
+}
+
+}  // namespace