Bug 953296 - Implement mozilla::IsClass and mozilla::IsEmpty. r=jcranmer
authorJeff Walden <jwalden@mit.edu>
Mon, 30 Dec 2013 01:07:39 -0600
changeset 178181 25252ec3c38e5d33eb2a3d068784ee684884b453
parent 178180 e40099b1ffa219bb620dd565763b7f906d7144cf
child 178182 96440758eb96ae5b10775b2a8b60d5e60b568163
push id3343
push userffxbld
push dateMon, 17 Mar 2014 21:55:32 +0000
treeherdermozilla-beta@2f7d3415f79f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjcranmer
bugs953296
milestone29.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 953296 - Implement mozilla::IsClass and mozilla::IsEmpty. r=jcranmer
mfbt/TypeTraits.h
mfbt/tests/TestTypeTraits.cpp
--- a/mfbt/TypeTraits.h
+++ b/mfbt/TypeTraits.h
@@ -164,16 +164,43 @@ struct IsEnumHelper
  * mozilla::IsEnum<enum S*>::value is false;
  * mozilla::IsEnum<int>::value is false;
  */
 template<typename T>
 struct IsEnum
   : detail::IsEnumHelper<typename RemoveCV<T>::Type>
 {};
 
+namespace detail {
+
+// __is_class is a supported extension across all of our supported compilers:
+// http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html
+// http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits
+// http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx
+template<typename T>
+struct IsClassHelper
+  : IntegralConstant<bool, __is_class(T)>
+{};
+
+} // namespace detail
+
+/**
+ * IsClass determines whether a type is a class type (but not a union).
+ *
+ * struct S {};
+ * union U {};
+ * mozilla::IsClass<int>::value is false;
+ * mozilla::IsClass<const S>::value is true;
+ * mozilla::IsClass<U>::value is false;
+ */
+template<typename T>
+struct IsClass
+  : detail::IsClassHelper<typename RemoveCV<T>::Type>
+{};
+
 /* 20.9.4.2 Composite type traits [meta.unary.comp] */
 
 /**
  * IsArithmetic determines whether a type is arithmetic.  A type is arithmetic
  * iff it is an integral type or a floating point type.
  *
  * mozilla::IsArithmetic<int>::value is true;
  * mozilla::IsArithmetic<double>::value is true;
@@ -240,16 +267,74 @@ template<> struct IsPod<double>         
 template<> struct IsPod<wchar_t>            : TrueType {};
 #ifdef MOZ_CHAR16_IS_NOT_WCHAR
 template<> struct IsPod<char16_t>           : TrueType {};
 #endif
 template<typename T> struct IsPod<T*>       : TrueType {};
 
 namespace detail {
 
+// __is_empty is a supported extension across all of our supported compilers:
+// http://llvm.org/releases/3.0/docs/ClangReleaseNotes.html
+// http://gcc.gnu.org/onlinedocs/gcc-4.4.7/gcc/Type-Traits.html#Type-Traits
+// http://msdn.microsoft.com/en-us/library/ms177194%28v=vs.100%29.aspx
+template<typename T>
+struct IsEmptyHelper
+  : IntegralConstant<bool, IsClass<T>::value && __is_empty(T)>
+{};
+
+} // namespace detail
+
+/**
+ * IsEmpty determines whether a type is a class (but not a union) that is empty.
+ *
+ * A class is empty iff it and all its base classes have no non-static data
+ * members (except bit-fields of length 0) and no virtual member functions, and
+ * no base class is empty or a virtual base class.
+ *
+ * Intuitively, empty classes don't have any data that has to be stored in
+ * instances of those classes.  (The size of the class must still be non-zero,
+ * because distinct array elements of any type must have different addresses.
+ * However, if the Empty Base Optimization is implemented by the compiler [most
+ * compilers implement it, and in certain cases C++11 requires it], the size of
+ * a class inheriting from an empty |Base| class need not be inflated by
+ * |sizeof(Base)|.)  And intuitively, non-empty classes have data members and/or
+ * vtable pointers that must be stored in each instance for proper behavior.
+ *
+ *   static_assert(!mozilla::IsEmpty<int>::value, "not a class => not empty");
+ *   union U1 { int x; };
+ *   static_assert(!mozilla::IsEmpty<U1>::value, "not a class => not empty");
+ *   struct E1 {};
+ *   struct E2 { int : 0 };
+ *   struct E3 : E1 {};
+ *   struct E4 : E2 {};
+ *   static_assert(mozilla::IsEmpty<E1>::value &&
+ *                 mozilla::IsEmpty<E2>::value &&
+ *                 mozilla::IsEmpty<E3>::value &&
+ *                 mozilla::IsEmpty<E4>::value,
+ *                 "all empty");
+ *   union U2 { E1 e1; };
+ *   static_assert(!mozilla::IsEmpty<U2>::value, "not a class => not empty");
+ *   struct NE1 { int x; };
+ *   struct NE2 : virtual E1 {};
+ *   struct NE3 : E2 { virtual ~NE3() {} };
+ *   struct NE4 { virtual void f() {} };
+ *   static_assert(!mozilla::IsEmpty<NE1>::value &&
+ *                 !mozilla::IsEmpty<NE2>::value &&
+ *                 !mozilla::IsEmpty<NE3>::value &&
+ *                 !mozilla::IsEmpty<NE4>::value,
+ *                 "all empty");
+ */
+template<typename T>
+struct IsEmpty : detail::IsEmptyHelper<typename RemoveCV<T>::Type>
+{};
+
+
+namespace detail {
+
 template<typename T, bool = IsFloatingPoint<T>::value>
 struct IsSignedHelper;
 
 template<typename T>
 struct IsSignedHelper<T, true> : TrueType {};
 
 template<typename T>
 struct IsSignedHelper<T, false>
--- a/mfbt/tests/TestTypeTraits.cpp
+++ b/mfbt/tests/TestTypeTraits.cpp
@@ -2,23 +2,64 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Assertions.h"
 #include "mozilla/TypeTraits.h"
 
 using mozilla::IsBaseOf;
+using mozilla::IsClass;
 using mozilla::IsConvertible;
+using mozilla::IsEmpty;
 using mozilla::IsSame;
 using mozilla::IsSigned;
 using mozilla::IsUnsigned;
 using mozilla::MakeSigned;
 using mozilla::MakeUnsigned;
 
+struct S1 {};
+union U1 { int x; };
+
+static_assert(!IsClass<int>::value, "int isn't a class");
+static_assert(IsClass<const S1>::value, "S is a class");
+static_assert(!IsClass<U1>::value, "U isn't a class");
+
+static_assert(!mozilla::IsEmpty<int>::value, "not a class => not empty");
+static_assert(!mozilla::IsEmpty<bool[5]>::value, "not a class => not empty");
+
+static_assert(!mozilla::IsEmpty<U1>::value, "not a class => not empty");
+
+struct E1 {};
+struct E2 { int : 0; };
+struct E3 : E1 {};
+struct E4 : E2 {};
+
+static_assert(IsEmpty<const volatile S1>::value, "S should be empty");
+
+static_assert(mozilla::IsEmpty<E1>::value &&
+              mozilla::IsEmpty<E2>::value &&
+              mozilla::IsEmpty<E3>::value &&
+              mozilla::IsEmpty<E4>::value,
+              "all empty");
+
+union U2 { E1 e1; };
+static_assert(!mozilla::IsEmpty<U2>::value, "not a class => not empty");
+
+struct NE1 { int x; };
+struct NE2 : virtual E1 {};
+struct NE3 : E2 { virtual ~NE3() {} };
+struct NE4 { virtual void f() {} };
+
+static_assert(!mozilla::IsEmpty<NE1>::value &&
+              !mozilla::IsEmpty<NE2>::value &&
+              !mozilla::IsEmpty<NE3>::value &&
+              !mozilla::IsEmpty<NE4>::value,
+              "all empty");
+
 static_assert(!IsSigned<bool>::value, "bool shouldn't be signed");
 static_assert(IsUnsigned<bool>::value, "bool should be unsigned");
 
 static_assert(!IsSigned<const bool>::value, "const bool shouldn't be signed");
 static_assert(IsUnsigned<const bool>::value, "const bool should be unsigned");
 
 static_assert(!IsSigned<volatile bool>::value, "volatile bool shouldn't be signed");
 static_assert(IsUnsigned<volatile bool>::value, "volatile bool should be unsigned");