mfbt/TypedEnum.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /* Macros to emulate C++11 typed enums and enum classes. */
     9 #ifndef mozilla_TypedEnum_h
    10 #define mozilla_TypedEnum_h
    12 #include "mozilla/TypedEnumInternal.h"
    13 #include "mozilla/MacroArgs.h"
    15 #if defined(__cplusplus)
    17 /**
    18  * MOZ_ENUM_TYPE specifies the underlying numeric type for an enum.  It's
    19  * specified by placing MOZ_ENUM_TYPE(type) immediately after the enum name in
    20  * its declaration, and before the opening curly brace, like
    21  *
    22  *   enum MyEnum MOZ_ENUM_TYPE(uint16_t)
    23  *   {
    24  *     A,
    25  *     B = 7,
    26  *     C
    27  *   };
    28  *
    29  * In supporting compilers, the macro will expand to ": uint16_t".  The
    30  * compiler will allocate exactly two bytes for MyEnum and will require all
    31  * enumerators to have values between 0 and 65535.  (Thus specifying "B =
    32  * 100000" instead of "B = 7" would fail to compile.)  In old compilers the
    33  * macro expands to the empty string, and the underlying type is generally
    34  * undefined.
    35  */
    36 #ifdef MOZ_HAVE_CXX11_ENUM_TYPE
    37 #  define MOZ_ENUM_TYPE(type)   : type
    38 #else
    39 #  define MOZ_ENUM_TYPE(type)   /* no support */
    40 #endif
    42 /**
    43  * MOZ_BEGIN_ENUM_CLASS and MOZ_END_ENUM_CLASS provide access to the
    44  * strongly-typed enumeration feature of C++11 ("enum class").  If supported
    45  * by the compiler, an enum defined using these macros will not be implicitly
    46  * converted to any other type, and its enumerators will be scoped using the
    47  * enumeration name.  Place MOZ_BEGIN_ENUM_CLASS(EnumName [, type]) in place of
    48  * "enum EnumName {", and MOZ_END_ENUM_CLASS(EnumName) in place of the closing
    49  * "};".  For example,
    50  *
    51  *   MOZ_BEGIN_ENUM_CLASS(Enum, int32_t)
    52  *     A,
    53  *     B = 6
    54  *   MOZ_END_ENUM_CLASS(Enum)
    55  *
    56  * This will make "Enum::A" and "Enum::B" appear in the global scope, but "A"
    57  * and "B" will not.  In compilers that support C++11 strongly-typed
    58  * enumerations, implicit conversions of Enum values to numeric types will
    59  * fail.  In other compilers, Enum itself will actually be defined as a class,
    60  * and some implicit conversions will fail while others will succeed.
    61  *
    62  * The optional type argument specifies the underlying type for the enum where
    63  * supported, as with MOZ_ENUM_TYPE().  As with MOZ_ENUM_TYPE(), it will do
    64  * nothing on compilers that do not support it.
    65  *
    66  * MOZ_{BEGIN,END}_ENUM_CLASS doesn't work for defining enum classes nested
    67  * inside classes.  To define an enum class nested inside another class, use
    68  * MOZ_{BEGIN,END}_NESTED_ENUM_CLASS, and place a MOZ_FINISH_NESTED_ENUM_CLASS
    69  * in namespace scope to handle bits that can only be implemented with
    70  * namespace-scoped code.  For example:
    71  *
    72  *   class FooBar {
    73  *
    74  *     MOZ_BEGIN_NESTED_ENUM_CLASS(Enum, int32_t)
    75  *       A,
    76  *       B = 6
    77  *     MOZ_END_NESTED_ENUM_CLASS(Enum)
    78  *
    79  *   };
    80  *
    81  *   MOZ_FINISH_NESTED_ENUM_CLASS(FooBar::Enum)
    82  */
    83 #if defined(MOZ_HAVE_CXX11_STRONG_ENUMS)
    84   /*
    85    * All compilers that support strong enums also support an explicit
    86    * underlying type, so no extra check is needed.
    87    */
    89    /* Single-argument form. */
    90 #  define MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER1(Name) \
    91      enum class Name {
    92    /* Two-argument form. */
    93 #  define MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER2(Name, type) \
    94      enum class Name : type {
    95 #  define MOZ_END_NESTED_ENUM_CLASS(Name) \
    96      };
    97 #  define MOZ_FINISH_NESTED_ENUM_CLASS(Name) /* nothing */
    99   /*
   100    * MOZ_ENUM_CLASS_ENUM_TYPE allows using enum classes
   101    * as template parameter types. For that, we need integer types.
   102    * In the present case where the compiler supports strong enums,
   103    * these are already integer types so there is nothing more to do.
   104    */
   105 #  define MOZ_ENUM_CLASS_ENUM_TYPE(Name) Name
   106   /*
   107    * See the comment below about MOZ_TEMPLATE_ENUM_CLASS_ENUM_TYPE.
   108    */
   109 #  define MOZ_TEMPLATE_ENUM_CLASS_ENUM_TYPE(Name) Name
   110 #else
   111    /**
   112     * We need Name to both name a type, and scope the provided enumerator
   113     * names.  Namespaces and classes both provide scoping, but namespaces
   114     * aren't types, so we need to use a class that wraps the enum values.  We
   115     * have an implicit conversion from the inner enum type to the class, so
   116     * statements like
   117     *
   118     *   Enum x = Enum::A;
   119     *
   120     * will still work.  We need to define an implicit conversion from the class
   121     * to the inner enum as well, so that (for instance) switch statements will
   122     * work.  This means that the class can be implicitly converted to a numeric
   123     * value as well via the enum type, since C++ allows an implicit
   124     * user-defined conversion followed by a standard conversion to still be
   125     * implicit.
   126     *
   127     * We have an explicit constructor from int defined, so that casts like
   128     * (Enum)7 will still work.  We also have a zero-argument constructor with
   129     * no arguments, so declaration without initialization (like "Enum foo;")
   130     * will work.
   131     *
   132     * Additionally, we'll delete as many operators as possible for the inner
   133     * enum type, so statements like this will still fail:
   134     *
   135     *   f(5 + Enum::B); // deleted operator+
   136     *
   137     * But we can't prevent things like this, because C++ doesn't allow
   138     * overriding conversions or assignment operators for enums:
   139     *
   140     *   int x = Enum::A;
   141     *   int f()
   142     *   {
   143     *     return Enum::A;
   144     *   }
   145     */
   147    /* Single-argument form. */
   148 #  define MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER1(Name) \
   149      class Name \
   150      { \
   151        public: \
   152          enum Enum \
   153          {
   154    /* Two-argument form. */
   155 #  define MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER2(Name, type) \
   156      class Name \
   157      { \
   158        public: \
   159          enum Enum MOZ_ENUM_TYPE(type) \
   160          {
   161 #  define MOZ_END_NESTED_ENUM_CLASS(Name) \
   162          }; \
   163          Name() {} \
   164          MOZ_CONSTEXPR Name(Enum aEnum) : mEnum(aEnum) {} \
   165          template<typename Other> \
   166          explicit MOZ_CONSTEXPR Name(Other num) : mEnum((Enum)num) {} \
   167          MOZ_CONSTEXPR operator Enum() const { return mEnum; } \
   168          explicit MOZ_CONSTEXPR Name(const mozilla::CastableTypedEnumResult<Name>& aOther) \
   169            : mEnum(aOther.get()) \
   170          {} \
   171        private: \
   172          Enum mEnum; \
   173      };
   174 #  define MOZ_FINISH_NESTED_ENUM_CLASS(Name) \
   175      inline int operator+(const int&, const Name::Enum&) MOZ_DELETE; \
   176      inline int operator+(const Name::Enum&, const int&) MOZ_DELETE; \
   177      inline int operator-(const int&, const Name::Enum&) MOZ_DELETE; \
   178      inline int operator-(const Name::Enum&, const int&) MOZ_DELETE; \
   179      inline int operator*(const int&, const Name::Enum&) MOZ_DELETE; \
   180      inline int operator*(const Name::Enum&, const int&) MOZ_DELETE; \
   181      inline int operator/(const int&, const Name::Enum&) MOZ_DELETE; \
   182      inline int operator/(const Name::Enum&, const int&) MOZ_DELETE; \
   183      inline int operator%(const int&, const Name::Enum&) MOZ_DELETE; \
   184      inline int operator%(const Name::Enum&, const int&) MOZ_DELETE; \
   185      inline int operator+(const Name::Enum&) MOZ_DELETE; \
   186      inline int operator-(const Name::Enum&) MOZ_DELETE; \
   187      inline int& operator++(Name::Enum&) MOZ_DELETE; \
   188      inline int operator++(Name::Enum&, int) MOZ_DELETE; \
   189      inline int& operator--(Name::Enum&) MOZ_DELETE; \
   190      inline int operator--(Name::Enum&, int) MOZ_DELETE; \
   191      inline bool operator==(const int&, const Name::Enum&) MOZ_DELETE; \
   192      inline bool operator==(const Name::Enum&, const int&) MOZ_DELETE; \
   193      inline bool operator!=(const int&, const Name::Enum&) MOZ_DELETE; \
   194      inline bool operator!=(const Name::Enum&, const int&) MOZ_DELETE; \
   195      inline bool operator>(const int&, const Name::Enum&) MOZ_DELETE; \
   196      inline bool operator>(const Name::Enum&, const int&) MOZ_DELETE; \
   197      inline bool operator<(const int&, const Name::Enum&) MOZ_DELETE; \
   198      inline bool operator<(const Name::Enum&, const int&) MOZ_DELETE; \
   199      inline bool operator>=(const int&, const Name::Enum&) MOZ_DELETE; \
   200      inline bool operator>=(const Name::Enum&, const int&) MOZ_DELETE; \
   201      inline bool operator<=(const int&, const Name::Enum&) MOZ_DELETE; \
   202      inline bool operator<=(const Name::Enum&, const int&) MOZ_DELETE; \
   203      inline bool operator!(const Name::Enum&) MOZ_DELETE; \
   204      inline bool operator&&(const bool&, const Name::Enum&) MOZ_DELETE; \
   205      inline bool operator&&(const Name::Enum&, const bool&) MOZ_DELETE; \
   206      inline bool operator||(const bool&, const Name::Enum&) MOZ_DELETE; \
   207      inline bool operator||(const Name::Enum&, const bool&) MOZ_DELETE; \
   208      inline int operator&(const int&, const Name::Enum&) MOZ_DELETE; \
   209      inline int operator&(const Name::Enum&, const int&) MOZ_DELETE; \
   210      inline int operator|(const int&, const Name::Enum&) MOZ_DELETE; \
   211      inline int operator|(const Name::Enum&, const int&) MOZ_DELETE; \
   212      inline int operator^(const int&, const Name::Enum&) MOZ_DELETE; \
   213      inline int operator^(const Name::Enum&, const int&) MOZ_DELETE; \
   214      inline int operator<<(const int&, const Name::Enum&) MOZ_DELETE; \
   215      inline int operator<<(const Name::Enum&, const int&) MOZ_DELETE; \
   216      inline int operator>>(const int&, const Name::Enum&) MOZ_DELETE; \
   217      inline int operator>>(const Name::Enum&, const int&) MOZ_DELETE; \
   218      inline int& operator+=(int&, const Name::Enum&) MOZ_DELETE; \
   219      inline int& operator-=(int&, const Name::Enum&) MOZ_DELETE; \
   220      inline int& operator*=(int&, const Name::Enum&) MOZ_DELETE; \
   221      inline int& operator/=(int&, const Name::Enum&) MOZ_DELETE; \
   222      inline int& operator%=(int&, const Name::Enum&) MOZ_DELETE; \
   223      inline int& operator&=(int&, const Name::Enum&) MOZ_DELETE; \
   224      inline int& operator|=(int&, const Name::Enum&) MOZ_DELETE; \
   225      inline int& operator^=(int&, const Name::Enum&) MOZ_DELETE; \
   226      inline int& operator<<=(int&, const Name::Enum&) MOZ_DELETE; \
   227      inline int& operator>>=(int&, const Name::Enum&) MOZ_DELETE;
   229   /*
   230    * MOZ_ENUM_CLASS_ENUM_TYPE allows using enum classes
   231    * as template parameter types. For that, we need integer types.
   232    * In the present case, the integer type is the Enum nested type.
   233    */
   234 #  define MOZ_ENUM_CLASS_ENUM_TYPE(Name) Name::Enum
   235   /*
   236    * MOZ_TEMPLATE_ENUM_CLASS_ENUM_TYPE is a variant of MOZ_ENUM_CLASS_ENUM_TYPE
   237    * to be used when the enum class at hand depends on template parameters.
   238    *
   239    * Indeed, if T depends on template parameters, in order to name a nested type
   240    * in T, C++ does not allow to just write "T::NestedType". Instead, we have
   241    * to write "typename T::NestedType". The role of this macro is to add
   242    * this "typename" keywords where needed.
   243    *
   244    * Example:
   245    *
   246    *    template<typename T, MOZ_TEMPLATE_ENUM_CLASS_ENUM_TYPE(T) Value>
   247    *    struct S {};
   248    *
   249    *    MOZ_BEGIN_ENUM_CLASS(E)
   250    *      Foo,
   251    *      Bar
   252    *    MOZ_END_ENUM_CLASS(E)
   253    *
   254    *    S<E, E::Bar> s;
   255    *
   256    * In this example, the second template parameter to S is meant to be of type T,
   257    * but on non-C++11 compilers, type T is a class type, not an integer type, so
   258    * it is not accepted as the type of a constant template parameter. One would
   259    * then want to use MOZ_ENUM_CLASS_ENUM_TYPE(T), but that doesn't work either
   260    * as T depends on template parameters (more specifically here, T _is_ a template
   261    * parameter) so as MOZ_ENUM_CLASS_ENUM_TYPE(T) expands to T::Enum, we are missing
   262    * the required "typename" keyword. So here, MOZ_TEMPLATE_ENUM_CLASS_ENUM_TYPE
   263    * is needed.
   264    */
   265 #  define MOZ_TEMPLATE_ENUM_CLASS_ENUM_TYPE(Name) typename Name::Enum
   266 #endif
   268 #  define MOZ_BEGIN_NESTED_ENUM_CLASS_GLUE(a, b) a b
   269 #  define MOZ_BEGIN_NESTED_ENUM_CLASS(...) \
   270      MOZ_BEGIN_NESTED_ENUM_CLASS_GLUE( \
   271        MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER, \
   272                                       __VA_ARGS__), \
   273        (__VA_ARGS__))
   275 #  define MOZ_BEGIN_ENUM_CLASS(...) MOZ_BEGIN_NESTED_ENUM_CLASS(__VA_ARGS__)
   276 #  define MOZ_END_ENUM_CLASS(Name) \
   277      MOZ_END_NESTED_ENUM_CLASS(Name) \
   278      MOZ_FINISH_NESTED_ENUM_CLASS(Name)
   280 #endif /* __cplusplus */
   282 #endif /* mozilla_TypedEnum_h */

mercurial