diff options
-rw-r--r-- | Android.mk | 16 | ||||
-rw-r--r-- | brillo/any.cc | 6 | ||||
-rw-r--r-- | brillo/any.h | 22 | ||||
-rw-r--r-- | brillo/any_internal_impl.h | 8 | ||||
-rw-r--r-- | brillo/any_internal_impl_unittest.cc | 31 | ||||
-rw-r--r-- | brillo/any_unittest.cc | 14 | ||||
-rw-r--r-- | brillo/dbus/exported_property_set_unittest.cc | 2 | ||||
-rw-r--r-- | brillo/type_name_undecorate.cc | 35 | ||||
-rw-r--r-- | brillo/type_name_undecorate.h | 44 | ||||
-rw-r--r-- | brillo/type_name_undecorate_unittest.cc | 61 | ||||
-rw-r--r-- | libbrillo.gypi | 1 |
11 files changed, 175 insertions, 65 deletions
@@ -122,6 +122,7 @@ libbrillo_test_sources := \ brillo/streams/stream_unittest.cc \ brillo/streams/stream_utils_unittest.cc \ brillo/strings/string_utils_unittest.cc \ + brillo/type_name_undecorate_unittest.cc \ brillo/unittest_utils.cc \ brillo/url_utils_unittest.cc \ @@ -159,7 +160,6 @@ LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) LOCAL_STATIC_LIBRARIES := libmodpb64 LOCAL_CFLAGS := $(libbrillo_CFLAGS) LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS) -LOCAL_RTTI_FLAG := -frtti LOCAL_CLANG := true LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) include $(BUILD_SHARED_LIBRARY) @@ -175,7 +175,6 @@ LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) \ libbinder libutils LOCAL_CFLAGS := $(libbrillo_CFLAGS) LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS) -LOCAL_RTTI_FLAG := -frtti LOCAL_CLANG := true LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) include $(BUILD_SHARED_LIBRARY) @@ -193,7 +192,6 @@ LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo \ libchrome-dbus libdbus LOCAL_CFLAGS := $(libbrillo_CFLAGS) LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS) -LOCAL_RTTI_FLAG := -frtti LOCAL_CLANG := true LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) external/dbus include $(BUILD_SHARED_LIBRARY) @@ -212,7 +210,6 @@ LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo \ libminijail LOCAL_CFLAGS := $(libbrillo_CFLAGS) LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS) -LOCAL_RTTI_FLAG := -frtti LOCAL_CLANG := true LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) include $(BUILD_SHARED_LIBRARY) @@ -228,7 +225,6 @@ LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo \ libcrypto libssl LOCAL_CFLAGS := $(libbrillo_CFLAGS) LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS) -LOCAL_RTTI_FLAG := -frtti LOCAL_CLANG := true LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) include $(BUILD_SHARED_LIBRARY) @@ -244,7 +240,6 @@ LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo \ libbrillo-stream libcurl LOCAL_CFLAGS := $(libbrillo_CFLAGS) LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS) -LOCAL_RTTI_FLAG := -frtti LOCAL_CLANG := true LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) include $(BUILD_SHARED_LIBRARY) @@ -259,7 +254,6 @@ LOCAL_C_INCLUDES := $(libbrillo_includes) LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) LOCAL_CFLAGS := $(libbrillo_CFLAGS) LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS) -LOCAL_RTTI_FLAG := -frtti LOCAL_CLANG := true LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) include $(BUILD_SHARED_LIBRARY) @@ -276,7 +270,6 @@ LOCAL_STATIC_LIBRARIES := libmodpb64 LOCAL_CFLAGS := $(libbrillo_CFLAGS) LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS) LOCAL_CLANG := true -LOCAL_RTTI_FLAG := -frtti LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) include $(BUILD_STATIC_LIBRARY) @@ -293,7 +286,6 @@ LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo libcurl \ LOCAL_CFLAGS := $(libbrillo_CFLAGS) LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS) -Wno-sign-compare LOCAL_CLANG := true -LOCAL_RTTI_FLAG := -frtti LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) include $(BUILD_STATIC_LIBRARY) @@ -308,7 +300,6 @@ LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) LOCAL_STATIC_LIBRARIES := libmodpb64-host LOCAL_CFLAGS := $(libbrillo_CFLAGS) LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS) -LOCAL_RTTI_FLAG := -frtti LOCAL_CLANG := true LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) include $(BUILD_HOST_SHARED_LIBRARY) @@ -326,7 +317,6 @@ LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo \ libcrypto-host libssl-host LOCAL_CFLAGS := $(libbrillo_CFLAGS) LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS) -LOCAL_RTTI_FLAG := -frtti LOCAL_CLANG := true LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) include $(BUILD_HOST_SHARED_LIBRARY) @@ -342,7 +332,6 @@ LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo \ libbrillo-stream libcurl-host LOCAL_CFLAGS := $(libbrillo_CFLAGS) LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS) -LOCAL_RTTI_FLAG := -frtti LOCAL_CLANG := true LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) include $(BUILD_HOST_SHARED_LIBRARY) @@ -366,7 +355,7 @@ LOCAL_C_INCLUDES := \ LOCAL_STATIC_LIBRARIES := libgtest libchrome_test_helpers \ libbrillo-test-helpers libgmock libBionicGtestMain LOCAL_SHARED_LIBRARIES := $(libbrillo_shared_libraries) libbrillo libcurl \ - libbrillo-http libbrillo-stream libcrypto libprotobuf-cpp-lite-rtti + libbrillo-http libbrillo-stream libcrypto libprotobuf-cpp-lite ifeq ($(BRILLO_USE_DBUS),1) LOCAL_SRC_FILES += $(libbrillo_dbus_test_sources) LOCAL_STATIC_LIBRARIES += libchrome_dbus_test_helpers @@ -375,7 +364,6 @@ endif # BRILLO_USE_DBUS == 1 LOCAL_CFLAGS := $(libbrillo_CFLAGS) LOCAL_CPPFLAGS := $(libbrillo_CPPFLAGS) -Wno-sign-compare LOCAL_CLANG := true -LOCAL_RTTI_FLAG := -frtti include $(BUILD_NATIVE_TEST) # Run unit tests on target diff --git a/brillo/any.cc b/brillo/any.cc index d2313c5..f84badf 100644 --- a/brillo/any.cc +++ b/brillo/any.cc @@ -34,7 +34,7 @@ Any& Any::operator=(Any&& rhs) { bool Any::operator==(const Any& rhs) const { // Make sure both objects contain data of the same type. - if (strcmp(GetTypeNameInternal(), rhs.GetTypeNameInternal()) != 0) + if (strcmp(GetTypeTagInternal(), rhs.GetTypeTagInternal()) != 0) return false; if (IsEmpty()) @@ -43,9 +43,9 @@ bool Any::operator==(const Any& rhs) const { return data_buffer_.GetDataPtr()->CompareEqual(rhs.data_buffer_.GetDataPtr()); } -const char* Any::GetTypeNameInternal() const { +const char* Any::GetTypeTagInternal() const { if (!IsEmpty()) - return data_buffer_.GetDataPtr()->GetTypeName(); + return data_buffer_.GetDataPtr()->GetTypeTag(); return ""; } diff --git a/brillo/any.h b/brillo/any.h index feedc73..51016b5 100644 --- a/brillo/any.h +++ b/brillo/any.h @@ -83,8 +83,8 @@ class BRILLO_EXPORT Any final { // to make sure the requested type matches the type of data actually stored, // so this "canonical" type is used for type checking below. using CanonicalDestType = typename std::decay<DestType>::type; - const char* contained_type = GetTypeNameInternal(); - if (strcmp(typeid(CanonicalDestType).name(), contained_type) == 0) + const char* contained_type = GetTypeTagInternal(); + if (strcmp(GetTypeTag<CanonicalDestType>(), contained_type) == 0) return true; if (!std::is_pointer<CanonicalDestType>::value) @@ -97,17 +97,17 @@ class BRILLO_EXPORT Any final { using NonPointer = typename std::remove_pointer<CanonicalDestType>::type; using CanonicalDestTypeNoConst = typename std::add_pointer< typename std::remove_const<NonPointer>::type>::type; - if (strcmp(typeid(CanonicalDestTypeNoConst).name(), contained_type) == 0) + if (strcmp(GetTypeTag<CanonicalDestTypeNoConst>(), contained_type) == 0) return true; using CanonicalDestTypeNoVolatile = typename std::add_pointer< typename std::remove_volatile<NonPointer>::type>::type; - if (strcmp(typeid(CanonicalDestTypeNoVolatile).name(), contained_type) == 0) + if (strcmp(GetTypeTag<CanonicalDestTypeNoVolatile>(), contained_type) == 0) return true; using CanonicalDestTypeNoConstOrVolatile = typename std::add_pointer< typename std::remove_cv<NonPointer>::type>::type; - return strcmp(typeid(CanonicalDestTypeNoConstOrVolatile).name(), + return strcmp(GetTypeTag<CanonicalDestTypeNoConstOrVolatile>(), contained_type) == 0; } @@ -162,13 +162,9 @@ class BRILLO_EXPORT Any final { return TryGet<T>(typename std::decay<T>::type()); } - // Returns the name of the type contained within Any. The string is a mangled - // type name returned by type_info::name(). For most cases, instead of using - // this function, you should be calling IsTypeCompatible<>(). - inline std::string GetTypeName() const { return GetTypeNameInternal(); } // Returns the undecorated name of the type contained within Any. inline std::string GetUndecoratedTypeName() const { - return UndecorateTypeName(GetTypeNameInternal()); + return GetUndecoratedTypeNameForTag(GetTypeTagInternal()); } // Swaps the value of this object with that of |other|. void Swap(Any& other); @@ -196,9 +192,9 @@ class BRILLO_EXPORT Any final { void AppendToDBusMessageWriter(dbus::MessageWriter* writer) const; private: - // Internal implementation of GetTypeName() which returns just a char* to - // static type name buffer. - const char* GetTypeNameInternal() const; + // Returns a pointer to a static buffer containing type tag (sort of a type + // name) of the contained value. + const char* GetTypeTagInternal() const; // The data buffer for contained object. internal_details::Buffer data_buffer_; diff --git a/brillo/any_internal_impl.h b/brillo/any_internal_impl.h index d4fa39e..0154d4d 100644 --- a/brillo/any_internal_impl.h +++ b/brillo/any_internal_impl.h @@ -142,8 +142,8 @@ class Buffer; // Forward declaration of data buffer container. // Abstract base class for contained variant data. struct Data { virtual ~Data() {} - // Returns the type name for the contained data. - virtual const char* GetTypeName() const = 0; + // Returns the type tag (name) for the contained data. + virtual const char* GetTypeTag() const = 0; // Copies the contained data to the output |buffer|. virtual void CopyTo(Buffer* buffer) const = 0; // Moves the contained data to the output |buffer|. @@ -165,7 +165,7 @@ struct TypedData : public Data { // NOLINTNEXTLINE(build/c++11) explicit TypedData(T&& value) : value_(std::move(value)) {} - const char* GetTypeName() const override { return typeid(T).name(); } + const char* GetTypeTag() const override { return brillo::GetTypeTag<T>(); } void CopyTo(Buffer* buffer) const override; void MoveTo(Buffer* buffer) override; bool IsConvertibleToInteger() const override { @@ -268,7 +268,7 @@ class Buffer final { using Type = typename std::decay<T>::type; using DataType = TypedData<Type>; Data* ptr = GetDataPtr(); - if (ptr && strcmp(ptr->GetTypeName(), typeid(Type).name()) == 0) { + if (ptr && strcmp(ptr->GetTypeTag(), GetTypeTag<Type>()) == 0) { // We assign the data to the variant container, which already // has the data of the same type. Do fast copy/move with no memory // reallocation. diff --git a/brillo/any_internal_impl_unittest.cc b/brillo/any_internal_impl_unittest.cc index 4f39939..6f7f512 100644 --- a/brillo/any_internal_impl_unittest.cc +++ b/brillo/any_internal_impl_unittest.cc @@ -8,6 +8,7 @@ #include <gtest/gtest.h> using brillo::internal_details::Buffer; +using brillo::GetTypeTag; TEST(Buffer, Empty) { Buffer buffer; @@ -21,7 +22,7 @@ TEST(Buffer, Store_Int) { buffer.Assign(2); EXPECT_FALSE(buffer.IsEmpty()); EXPECT_EQ(Buffer::kContained, buffer.storage_); - EXPECT_STREQ(typeid(int).name(), buffer.GetDataPtr()->GetTypeName()); + EXPECT_STREQ(GetTypeTag<int>(), buffer.GetDataPtr()->GetTypeTag()); } TEST(Buffer, Store_Double) { @@ -29,7 +30,7 @@ TEST(Buffer, Store_Double) { buffer.Assign(2.3); EXPECT_FALSE(buffer.IsEmpty()); EXPECT_EQ(Buffer::kContained, buffer.storage_); - EXPECT_STREQ(typeid(double).name(), buffer.GetDataPtr()->GetTypeName()); + EXPECT_STREQ(GetTypeTag<double>(), buffer.GetDataPtr()->GetTypeTag()); } TEST(Buffer, Store_Pointers) { @@ -38,14 +39,14 @@ TEST(Buffer, Store_Pointers) { buffer.Assign(nullptr); EXPECT_FALSE(buffer.IsEmpty()); EXPECT_EQ(Buffer::kContained, buffer.storage_); - EXPECT_STREQ(typeid(std::nullptr_t).name(), - buffer.GetDataPtr()->GetTypeName()); + EXPECT_STREQ(GetTypeTag<std::nullptr_t>(), + buffer.GetDataPtr()->GetTypeTag()); // char * buffer.Assign("abcd"); EXPECT_FALSE(buffer.IsEmpty()); EXPECT_EQ(Buffer::kContained, buffer.storage_); - EXPECT_STREQ(typeid(const char*).name(), buffer.GetDataPtr()->GetTypeName()); + EXPECT_STREQ(GetTypeTag<const char*>(), buffer.GetDataPtr()->GetTypeTag()); // pointer to non-trivial object class NonTrivial { @@ -55,7 +56,7 @@ TEST(Buffer, Store_Pointers) { buffer.Assign(&non_trivial); EXPECT_FALSE(buffer.IsEmpty()); EXPECT_EQ(Buffer::kContained, buffer.storage_); - EXPECT_STREQ(typeid(NonTrivial*).name(), buffer.GetDataPtr()->GetTypeName()); + EXPECT_STREQ(GetTypeTag<NonTrivial*>(), buffer.GetDataPtr()->GetTypeTag()); } TEST(Buffer, Store_NonTrivialObjects) { @@ -67,7 +68,7 @@ TEST(Buffer, Store_NonTrivialObjects) { buffer.Assign(non_trivial); EXPECT_FALSE(buffer.IsEmpty()); EXPECT_EQ(Buffer::kExternal, buffer.storage_); - EXPECT_STREQ(typeid(NonTrivial).name(), buffer.GetDataPtr()->GetTypeName()); + EXPECT_STREQ(GetTypeTag<NonTrivial>(), buffer.GetDataPtr()->GetTypeTag()); } TEST(Buffer, Store_Objects) { @@ -79,7 +80,7 @@ TEST(Buffer, Store_Objects) { buffer.Assign(small); EXPECT_FALSE(buffer.IsEmpty()); EXPECT_EQ(Buffer::kContained, buffer.storage_); - EXPECT_STREQ(typeid(Small).name(), buffer.GetDataPtr()->GetTypeName()); + EXPECT_STREQ(GetTypeTag<Small>(), buffer.GetDataPtr()->GetTypeTag()); struct Large { char c[20]; @@ -87,7 +88,7 @@ TEST(Buffer, Store_Objects) { buffer.Assign(large); EXPECT_FALSE(buffer.IsEmpty()); EXPECT_EQ(Buffer::kExternal, buffer.storage_); - EXPECT_STREQ(typeid(Large).name(), buffer.GetDataPtr()->GetTypeName()); + EXPECT_STREQ(GetTypeTag<Large>(), buffer.GetDataPtr()->GetTypeTag()); } TEST(Buffer, Copy) { @@ -98,8 +99,8 @@ TEST(Buffer, Copy) { buffer1.CopyTo(&buffer2); EXPECT_FALSE(buffer1.IsEmpty()); EXPECT_FALSE(buffer2.IsEmpty()); - EXPECT_STREQ(typeid(int).name(), buffer1.GetDataPtr()->GetTypeName()); - EXPECT_STREQ(typeid(int).name(), buffer2.GetDataPtr()->GetTypeName()); + EXPECT_STREQ(GetTypeTag<int>(), buffer1.GetDataPtr()->GetTypeTag()); + EXPECT_STREQ(GetTypeTag<int>(), buffer2.GetDataPtr()->GetTypeTag()); EXPECT_EQ(30, buffer1.GetData<int>()); EXPECT_EQ(30, buffer2.GetData<int>()); @@ -107,8 +108,8 @@ TEST(Buffer, Copy) { buffer1.CopyTo(&buffer2); EXPECT_FALSE(buffer1.IsEmpty()); EXPECT_FALSE(buffer2.IsEmpty()); - EXPECT_STREQ(typeid(std::string).name(), buffer1.GetDataPtr()->GetTypeName()); - EXPECT_STREQ(typeid(std::string).name(), buffer2.GetDataPtr()->GetTypeName()); + EXPECT_STREQ(GetTypeTag<std::string>(), buffer1.GetDataPtr()->GetTypeTag()); + EXPECT_STREQ(GetTypeTag<std::string>(), buffer2.GetDataPtr()->GetTypeTag()); EXPECT_EQ("abc", buffer1.GetData<std::string>()); EXPECT_EQ("abc", buffer2.GetData<std::string>()); } @@ -128,7 +129,7 @@ TEST(Buffer, Move) { // the data and any retains the actual type. EXPECT_FALSE(buffer1.IsEmpty()); EXPECT_FALSE(buffer2.IsEmpty()); - EXPECT_STREQ(typeid(int).name(), buffer2.GetDataPtr()->GetTypeName()); + EXPECT_STREQ(GetTypeTag<int>(), buffer2.GetDataPtr()->GetTypeTag()); EXPECT_EQ(30, buffer2.GetData<int>()); buffer1.Assign(std::string("abc")); @@ -137,6 +138,6 @@ TEST(Buffer, Move) { // This will make the source object effectively "Empty". EXPECT_TRUE(buffer1.IsEmpty()); EXPECT_FALSE(buffer2.IsEmpty()); - EXPECT_STREQ(typeid(std::string).name(), buffer2.GetDataPtr()->GetTypeName()); + EXPECT_STREQ(GetTypeTag<std::string>(), buffer2.GetDataPtr()->GetTypeTag()); EXPECT_EQ("abc", buffer2.GetData<std::string>()); } diff --git a/brillo/any_unittest.cc b/brillo/any_unittest.cc index 2af8845..db89884 100644 --- a/brillo/any_unittest.cc +++ b/brillo/any_unittest.cc @@ -305,20 +305,6 @@ TEST(Any, Compare_NonComparable) { EXPECT_NE(person2, person3); } -TEST(Any, GetTypeName) { - Any val; - EXPECT_TRUE(val.GetTypeName().empty()); - - val = 1; - EXPECT_EQ(typeid(int).name(), val.GetTypeName()); - - val = 3.1415926; - EXPECT_EQ(typeid(double).name(), val.GetTypeName()); - - val = std::string("blah"); - EXPECT_EQ(typeid(std::string).name(), val.GetTypeName()); -} - TEST(Any, GetUndecoratedTypeName) { Any val; EXPECT_TRUE(val.GetUndecoratedTypeName().empty()); diff --git a/brillo/dbus/exported_property_set_unittest.cc b/brillo/dbus/exported_property_set_unittest.cc index c0deace..9233b4a 100644 --- a/brillo/dbus/exported_property_set_unittest.cc +++ b/brillo/dbus/exported_property_set_unittest.cc @@ -133,7 +133,7 @@ class ExportedPropertySetTest : public ::testing::Test { void AssertMethodReturnsError(dbus::MethodCall* method_call) { method_call->SetSerial(123); auto response = testing::CallMethod(p_->dbus_object_, method_call); - ASSERT_NE(dynamic_cast<dbus::ErrorResponse*>(response.get()), nullptr); + ASSERT_EQ(dbus::Message::MESSAGE_ERROR, response->GetMessageType()); } std::unique_ptr<dbus::Response> GetPropertyOnInterface( diff --git a/brillo/type_name_undecorate.cc b/brillo/type_name_undecorate.cc index 9a1d6a1..b588170 100644 --- a/brillo/type_name_undecorate.cc +++ b/brillo/type_name_undecorate.cc @@ -4,6 +4,8 @@ #include <brillo/type_name_undecorate.h> +#include <cstring> + #ifdef __GNUG__ #include <cstdlib> #include <cxxabi.h> @@ -30,4 +32,37 @@ std::string UndecorateTypeName(const char* type_name) { #endif } +std::string GetUndecoratedTypeNameForTag(const char* type_tag) { +#if defined(USE_RTTI_FOR_TYPE_TAGS) && \ + (defined(__cpp_rtti) || defined(__GXX_RTTI)) + return UndecorateTypeName(type_tag); +#else + // The signature of type tag for, say, 'int' would be the following: + // const char *brillo::GetTypeTag() [T = int] + // So we just need to extract the type name between '[T = ' and ']'. + const char* token = " = "; + const char* pos = std::strstr(type_tag, token); + if (!pos) + return type_tag; + std::string name = pos + std::strlen(token); + if (!name.empty() && name.back() == ']') + name.pop_back(); + return name; +#endif +} + +// Implementations of the explicitly instantiated GetTypeTag<T>() for common +// types. +template const char* GetTypeTag<int8_t>(); +template const char* GetTypeTag<uint8_t>(); +template const char* GetTypeTag<int16_t>(); +template const char* GetTypeTag<uint16_t>(); +template const char* GetTypeTag<int32_t>(); +template const char* GetTypeTag<uint32_t>(); +template const char* GetTypeTag<int64_t>(); +template const char* GetTypeTag<uint64_t>(); +template const char* GetTypeTag<bool>(); +template const char* GetTypeTag<double>(); +template const char* GetTypeTag<std::string>(); + } // namespace brillo diff --git a/brillo/type_name_undecorate.h b/brillo/type_name_undecorate.h index 8cf9030..c750e58 100644 --- a/brillo/type_name_undecorate.h +++ b/brillo/type_name_undecorate.h @@ -10,16 +10,58 @@ #include <brillo/brillo_export.h> +#if !defined(USE_RTTI_FOR_TYPE_TAGS) && !defined(__clang__) +// When type information is used with RTTI disabled, we rely on +// __PRETTY_FUNCTION__ macro for type tags. Unfortunately gcc and clang produce +// different signatures for types that have optional template parameters, such +// as std::vector and std::map. The problem arises when inter-operating between +// libraries that are compiled with different compilers. +// Since most of Brillo is compiled with clang, we choose clang here exclusively +// and prevent this code from compiling with GCC to avoid hidden runtime errors. +#error TypeInfo/Any with RTTI disabled is supported on clang compiler only. +#endif + namespace brillo { +template<typename T> +const char* GetTypeTag() { +#if defined(USE_RTTI_FOR_TYPE_TAGS) && \ + (defined(__cpp_rtti) || defined(__GXX_RTTI)) + return typeid(T).name(); +#else + // __PRETTY_FUNCTION__ would include the type T signature and therefore each + // instance of brillo::internal_details::GetTypeTag<T>() will have a different + // tag string. + return __PRETTY_FUNCTION__; +#endif +} + +// Explicitly instantiate GetTypeTag<T>() for common types to minimize static +// data segment pollution. +extern template BRILLO_EXPORT const char* GetTypeTag<int8_t>(); +extern template BRILLO_EXPORT const char* GetTypeTag<uint8_t>(); +extern template BRILLO_EXPORT const char* GetTypeTag<int16_t>(); +extern template BRILLO_EXPORT const char* GetTypeTag<uint16_t>(); +extern template BRILLO_EXPORT const char* GetTypeTag<int32_t>(); +extern template BRILLO_EXPORT const char* GetTypeTag<uint32_t>(); +extern template BRILLO_EXPORT const char* GetTypeTag<int64_t>(); +extern template BRILLO_EXPORT const char* GetTypeTag<uint64_t>(); +extern template BRILLO_EXPORT const char* GetTypeTag<bool>(); +extern template BRILLO_EXPORT const char* GetTypeTag<double>(); +extern template BRILLO_EXPORT const char* GetTypeTag<std::string>(); + // Use brillo::UndecorateTypeName() to obtain human-readable type from // the decorated/mangled type name returned by std::type_info::name(). BRILLO_EXPORT std::string UndecorateTypeName(const char* type_name); +// Returns undecorated type name for the given type tag. This will extract the +// actual type name from the type tag string. +BRILLO_EXPORT std::string GetUndecoratedTypeNameForTag(const char* type_tag); + // A template helper function that returns the undecorated type name for type T. template<typename T> inline std::string GetUndecoratedTypeName() { - return UndecorateTypeName(typeid(T).name()); + return GetUndecoratedTypeNameForTag(GetTypeTag<T>()); } } // namespace brillo diff --git a/brillo/type_name_undecorate_unittest.cc b/brillo/type_name_undecorate_unittest.cc new file mode 100644 index 0000000..04c1c5e --- /dev/null +++ b/brillo/type_name_undecorate_unittest.cc @@ -0,0 +1,61 @@ +// Copyright 2014 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <brillo/type_name_undecorate.h> + +#include <brillo/variant_dictionary.h> +#include <gtest/gtest.h> + +namespace brillo { + +TEST(TypeTags, GetTypeTag) { + EXPECT_STREQ("const char *brillo::GetTypeTag() [T = int]", GetTypeTag<int>()); + EXPECT_STREQ("const char *brillo::GetTypeTag() [T = std::__1::map<std::__1::" + "basic_string<char, std::__1::char_traits<char>, " + "std::__1::allocator<char> >, brillo::Any, std::__1::less<" + "std::__1::basic_string<char, std::__1::char_traits<char>, " + "std::__1::allocator<char> > >, std::__1::allocator<std::__1::" + "pair<const std::__1::basic_string<char, std::__1::char_traits" + "<char>, std::__1::allocator<char> >, brillo::Any> > >]", + GetTypeTag<VariantDictionary>()); + EXPECT_STREQ("const char *brillo::GetTypeTag() [T = int []]", + GetTypeTag<int[]>()); +} + +TEST(TypeDecoration, UndecorateTypeName) { + EXPECT_EQ("int", UndecorateTypeName("i")); + EXPECT_EQ("char const* brillo::GetTypeTag<unsigned long long>()", + UndecorateTypeName("_ZN6brillo10GetTypeTagIyEEPKcv")); + EXPECT_EQ("std::__1::to_string(int)", + UndecorateTypeName("_ZNSt3__19to_stringEi")); +} + +TEST(TypeDecoration, GetUndecoratedTypeNameForTag) { + EXPECT_EQ("int", + GetUndecoratedTypeNameForTag( + "const char *brillo::GetTypeTag() [T = int]")); + EXPECT_EQ("int []", + GetUndecoratedTypeNameForTag( + "const char *brillo::GetTypeTag() [T = int []]")); + EXPECT_EQ("foo::bar<int []>()", + GetUndecoratedTypeNameForTag( + "const char *brillo::GetTypeTag() [T = foo::bar<int []>()]")); +} + +TEST(TypeDecoration, GetUndecoratedTypeName) { + EXPECT_EQ("int", GetUndecoratedTypeName<int>()); + EXPECT_EQ("int *", GetUndecoratedTypeName<int*>()); + EXPECT_EQ("const int *", GetUndecoratedTypeName<const int*>()); + EXPECT_EQ("int []", GetUndecoratedTypeName<int[]>()); + EXPECT_EQ("bool", GetUndecoratedTypeName<bool>()); + EXPECT_EQ("char", GetUndecoratedTypeName<char>()); + EXPECT_EQ("float", GetUndecoratedTypeName<float>()); + EXPECT_EQ("double", GetUndecoratedTypeName<double>()); + EXPECT_EQ("long", GetUndecoratedTypeName<long>()); + EXPECT_EQ("std::__1::map<int, double, std::__1::less<int>, " + "std::__1::allocator<std::__1::pair<const int, double> > >", + (GetUndecoratedTypeName<std::map<int, double>>())); +} + +} // namespace brillo diff --git a/libbrillo.gypi b/libbrillo.gypi index 6dec2e4..d39290f 100644 --- a/libbrillo.gypi +++ b/libbrillo.gypi @@ -353,6 +353,7 @@ 'brillo/streams/stream_unittest.cc', 'brillo/streams/stream_utils_unittest.cc', 'brillo/strings/string_utils_unittest.cc', + 'brillo/type_name_undecorate_unittest.cc', 'brillo/unittest_utils.cc', 'brillo/url_utils_unittest.cc', 'brillo/variant_dictionary_unittest.cc', |