Bug 835542 - Add an IntegralConstant helper to TypeTraits.h, and use it where the spec says we should be using it. r=bjacob
authorJeff Walden <jwalden@mit.edu>
Sun, 16 Dec 2012 18:20:17 -0500
changeset 134110 645cf7ea0876a38cc9aead0fbabd408deca51109
parent 134109 1501761c97260bdc9f54202ec9ccc2f8c66bb950
child 134111 5a8b3e397ffcc45895074dfdc68ee4ed947ec8b0
push id2452
push userlsblakk@mozilla.com
push dateMon, 13 May 2013 16:59:38 +0000
treeherdermozilla-beta@d4b152d29d8d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbjacob
bugs835542
milestone22.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 835542 - Add an IntegralConstant helper to TypeTraits.h, and use it where the spec says we should be using it. r=bjacob
js/public/HashTable.h
js/src/frontend/ParseMaps.h
js/src/jsanalyze.h
mfbt/TypeTraits.h
--- a/js/public/HashTable.h
+++ b/js/public/HashTable.h
@@ -575,27 +575,23 @@ class HashMapEntry
     const Key key;
     Value value;
 };
 
 } // namespace js
 
 namespace mozilla {
 
-template <class T>
-struct IsPod<js::detail::HashTableEntry<T> >
-{
-    static const bool value = IsPod<T>::value;
-};
+template <typename T>
+struct IsPod<js::detail::HashTableEntry<T> > : IsPod<T> {};
 
-template <class K, class V>
+template <typename K, typename V>
 struct IsPod<js::HashMapEntry<K, V> >
-{
-    static const bool value = IsPod<K>::value && IsPod<V>::value;
-};
+  : IntegralConstant<bool, IsPod<K>::value && IsPod<V>::value>
+{};
 
 } // namespace mozilla
 
 namespace js {
 
 namespace detail {
 
 template <class T, class HashPolicy, class AllocPolicy>
--- a/js/src/frontend/ParseMaps.h
+++ b/js/src/frontend/ParseMaps.h
@@ -416,16 +416,13 @@ typedef AtomDefnListMap::Range  AtomDefn
 
 } /* namespace frontend */
 
 } /* namespace js */
 
 namespace mozilla {
 
 template <>
-struct IsPod<js::frontend::DefinitionList>
-{
-    static const bool value = true;
-};
+struct IsPod<js::frontend::DefinitionList> : TrueType {};
 
 } /* namespace mozilla */
 
 #endif
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -1288,17 +1288,17 @@ class CrossScriptSSA
 void PrintBytecode(JSContext *cx, HandleScript script, jsbytecode *pc);
 #endif
 
 } /* namespace analyze */
 } /* namespace js */
 
 namespace mozilla {
 
-template <> struct IsPod<js::analyze::LifetimeVariable> { static const bool value = true; };
-template <> struct IsPod<js::analyze::LoopAnalysis>     { static const bool value = true; };
-template <> struct IsPod<js::analyze::SlotValue>        { static const bool value = true; };
-template <> struct IsPod<js::analyze::SSAValue>         { static const bool value = true; };
-template <> struct IsPod<js::analyze::SSAUseChain>      { static const bool value = true; };
+template <> struct IsPod<js::analyze::LifetimeVariable> : TrueType {};
+template <> struct IsPod<js::analyze::LoopAnalysis>     : TrueType {};
+template <> struct IsPod<js::analyze::SlotValue>        : TrueType {};
+template <> struct IsPod<js::analyze::SSAValue>         : TrueType {};
+template <> struct IsPod<js::analyze::SSAUseChain>      : TrueType {};
 
 } /* namespace mozilla */
 
 #endif // jsanalyze_h___
--- a/mfbt/TypeTraits.h
+++ b/mfbt/TypeTraits.h
@@ -12,95 +12,126 @@
  * <type_traits> header.  Don't add traits not in that header!  When all
  * platforms provide that header, we can convert all users and remove this one.
  */
 
 #include <wchar.h>
 
 namespace mozilla {
 
+/**
+ * Helper class used as a base for various type traits, exposed publicly
+ * because <type_traits> exposes it as well.
+ */
+template<typename T, T Value>
+struct IntegralConstant
+{
+    static const T value = Value;
+    typedef T ValueType;
+    typedef IntegralConstant<T, Value> Type;
+};
+
+/** Convenient aliases. */
+typedef IntegralConstant<bool, true> TrueType;
+typedef IntegralConstant<bool, false> FalseType;
+
 namespace detail {
 
-/**
- * The trickery used to implement IsBaseOf here makes it possible to use it for
- * the cases of private and multiple inheritance.  This code was inspired by the
- * sample code here:
- *
- * http://stackoverflow.com/questions/2910979/how-is-base-of-works
- */
+// The trickery used to implement IsBaseOf here makes it possible to use it for
+// the cases of private and multiple inheritance.  This code was inspired by the
+// sample code here:
+//
+// http://stackoverflow.com/questions/2910979/how-is-base-of-works
 template<class Base, class Derived>
-class IsBaseOfHelper
+struct BaseOfHelper
 {
   public:
     operator Base*() const;
     operator Derived*();
 };
 
+template<class Base, class Derived>
+struct BaseOfTester
+{
+  private:
+    template<class T>
+    static char test(Derived*, T);
+    static int test(Base*, int);
+
+  public:
+    static const bool value =
+      sizeof(test(BaseOfHelper<Base, Derived>(), int())) == sizeof(char);
+};
+
+template<class Base, class Derived>
+struct BaseOfTester<Base, const Derived>
+{
+  private:
+    template<class T>
+    static char test(Derived*, T);
+    static int test(Base*, int);
+
+  public:
+    static const bool value =
+      sizeof(test(BaseOfHelper<Base, Derived>(), int())) == sizeof(char);
+};
+
+template<class Base, class Derived>
+struct BaseOfTester<Base&, Derived&> : FalseType {};
+
+template<class Type>
+struct BaseOfTester<Type, Type> : TrueType {};
+
+template<class Type>
+struct BaseOfTester<Type, const Type> : TrueType {};
+
 } /* namespace detail */
 
+template<bool Condition, typename A, typename B>
+struct Conditional;
+
 /*
  * IsBaseOf allows to know whether a given class is derived from another.
  *
  * Consider the following class definitions:
  *
  *   class A {};
  *   class B : public A {};
  *   class C {};
  *
  * mozilla::IsBaseOf<A, B>::value is true;
  * mozilla::IsBaseOf<A, C>::value is false;
  */
 template<class Base, class Derived>
-class IsBaseOf
+struct IsBaseOf
+  : Conditional<detail::BaseOfTester<Base, Derived>::value, TrueType, FalseType>::Type
+{};
+
+namespace detail {
+
+template<typename From, typename To>
+struct ConvertibleTester
 {
   private:
-    template<class T>
-    static char test(Derived*, T);
-    static int test(Base*, int);
+    static From create();
 
-  public:
-    static const bool value =
-      sizeof(test(detail::IsBaseOfHelper<Base, Derived>(), int())) == sizeof(char);
-};
+    template<typename From1, typename To1>
+    static char test(To to);
 
-template<class Base, class Derived>
-class IsBaseOf<Base, const Derived>
-{
-  private:
-    template<class T>
-    static char test(Derived*, T);
-    static int test(Base*, int);
+    template<typename From1, typename To1>
+    static int test(...);
 
   public:
     static const bool value =
-      sizeof(test(detail::IsBaseOfHelper<Base, Derived>(), int())) == sizeof(char);
-};
-
-template<class Base, class Derived>
-class IsBaseOf<Base&, Derived&>
-{
-  public:
-    static const bool value = false;
+      sizeof(test<From, To>(create())) == sizeof(char);
 };
 
-template<class Type>
-class IsBaseOf<Type, Type>
-{
-  public:
-    static const bool value = true;
-};
+} // namespace detail
 
-template<class Type>
-class IsBaseOf<Type, const Type>
-{
-  public:
-    static const bool value = true;
-};
-
-/*
+/**
  * IsConvertible determines whether a value of type From will implicitly convert
  * to a value of type To.  For example:
  *
  *   struct A {};
  *   struct B : public A {};
  *   struct C {};
  *
  * mozilla::IsConvertible<A, A>::value is true;
@@ -113,63 +144,51 @@ class IsBaseOf<Type, const Type>
  * mozilla::IsConvertible<C*, A*>::value is false.
  *
  * For obscure reasons, you can't use IsConvertible when the types being tested
  * are related through private inheritance, and you'll get a compile error if
  * you try.  Just don't do it!
  */
 template<typename From, typename To>
 struct IsConvertible
-{
-  private:
-    static From create();
-
-    template<typename From1, typename To1>
-    static char test(To to);
+  : Conditional<detail::ConvertibleTester<From, To>::value, TrueType, FalseType>::Type
+{};
 
-    template<typename From1, typename To1>
-    static int test(...);
-
-  public:
-    static const bool value =
-      sizeof(test<From, To>(create())) == sizeof(char);
-};
-
-/*
+/**
  * Conditional selects a class between two, depending on a given boolean value.
  *
  * mozilla::Conditional<true, A, B>::Type is A;
  * mozilla::Conditional<false, A, B>::Type is B;
  */
-template<bool condition, class A, class B>
+template<bool Condition, typename A, typename B>
 struct Conditional
 {
     typedef A Type;
 };
 
 template<class A, class B>
 struct Conditional<false, A, B>
 {
     typedef B Type;
 };
 
-/*
+/**
  * EnableIf is a struct containing a typedef of T if and only if B is true.
  *
  * mozilla::EnableIf<true, int>::Type is int;
  * mozilla::EnableIf<false, int>::Type is a compile-time error.
  *
  * Use this template to implement SFINAE-style (Substitution Failure Is not An
  * Error) requirements.  For example, you might use it to impose a restriction
  * on a template parameter:
  *
  *   template<typename T>
  *   class PodVector // vector optimized to store POD (memcpy-able) types
  *   {
- *      EnableIf<IsPod<T>, T>::Type* vector;
+ *      EnableIf<IsPod<T>::value, T>::Type* vector;
  *      size_t length;
  *      ...
  *   };
  */
 template<bool B, typename T = void>
 struct EnableIf
 {};
 
@@ -185,69 +204,60 @@ struct EnableIf<true, T>
  * mozilla::IsSame<int, int>::value is true;
  * mozilla::IsSame<int*, int*>::value is true;
  * mozilla::IsSame<int, unsigned int>::value is false;
  * mozilla::IsSame<void, void>::value is true;
  * mozilla::IsSame<const int, int>::value is false;
  * mozilla::IsSame<struct S, struct S>::value is true.
  */
 template<typename T, typename U>
-struct IsSame
-{
-    static const bool value = false;
-};
+struct IsSame : FalseType {};
 
 template<typename T>
-struct IsSame<T, T>
-{
-    static const bool value = true;
-};
+struct IsSame<T, T> : TrueType {};
 
-/*
- * Traits class for identifying POD types. Until C++0x, there is no automatic
- * way to detect PODs, so for the moment it is done manually.
+/**
+ * Traits class for identifying POD types.  Until C++11 there's no automatic
+ * way to detect PODs, so for the moment this is done manually.  Users may
+ * define specializations of this class that inherit from mozilla::TrueType and
+ * mozilla::FalseType (or equivalently mozilla::IntegralConstant<bool, true or
+ * false>, or conveniently from mozilla::IsPod for composite types) as needed to
+ * ensure correct IsPod behavior.
  */
 template<typename T>
-struct IsPod
-{
-    static const bool value = false;
-};
-template<> struct IsPod<char>               { static const bool value = true; };
-template<> struct IsPod<signed char>        { static const bool value = true; };
-template<> struct IsPod<unsigned char>      { static const bool value = true; };
-template<> struct IsPod<short>              { static const bool value = true; };
-template<> struct IsPod<unsigned short>     { static const bool value = true; };
-template<> struct IsPod<int>                { static const bool value = true; };
-template<> struct IsPod<unsigned int>       { static const bool value = true; };
-template<> struct IsPod<long>               { static const bool value = true; };
-template<> struct IsPod<unsigned long>      { static const bool value = true; };
-template<> struct IsPod<long long>          { static const bool value = true; };
-template<> struct IsPod<unsigned long long> { static const bool value = true; };
-template<> struct IsPod<bool>               { static const bool value = true; };
-template<> struct IsPod<float>              { static const bool value = true; };
-template<> struct IsPod<double>             { static const bool value = true; };
-template<> struct IsPod<wchar_t>            { static const bool value = true; };
-template<typename T> struct IsPod<T*>       { static const bool value = true; };
+struct IsPod : public FalseType {};
+
+template<> struct IsPod<char>               : TrueType {};
+template<> struct IsPod<signed char>        : TrueType {};
+template<> struct IsPod<unsigned char>      : TrueType {};
+template<> struct IsPod<short>              : TrueType {};
+template<> struct IsPod<unsigned short>     : TrueType {};
+template<> struct IsPod<int>                : TrueType {};
+template<> struct IsPod<unsigned int>       : TrueType {};
+template<> struct IsPod<long>               : TrueType {};
+template<> struct IsPod<unsigned long>      : TrueType {};
+template<> struct IsPod<long long>          : TrueType {};
+template<> struct IsPod<unsigned long long> : TrueType {};
+template<> struct IsPod<bool>               : TrueType {};
+template<> struct IsPod<float>              : TrueType {};
+template<> struct IsPod<double>             : TrueType {};
+template<> struct IsPod<wchar_t>            : TrueType {};
+template<typename T> struct IsPod<T*>       : TrueType {};
 
 /**
  * IsPointer determines whether a type is a pointer type (but not a pointer-to-
  * member type).
  *
  * mozilla::IsPointer<struct S*>::value is true;
  * mozilla::IsPointer<int**>::value is true;
  * mozilla::IsPointer<void (*)(void)>::value is true;
  * mozilla::IsPointer<int>::value is false;
  * mozilla::IsPointer<struct S>::value is false.
  */
 template<typename T>
-struct IsPointer
-{
-    static const bool value = false;
-};
+struct IsPointer : FalseType {};
+
 template<typename T>
-struct IsPointer<T*>
-{
-    static const bool value = true;
-};
+struct IsPointer<T*> : TrueType {};
 
 } /* namespace mozilla */
 
 #endif  /* mozilla_TypeTraits_h_ */