mfbt/TypedEnumInternal.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mfbt/TypedEnumInternal.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,112 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/* Internal stuff needed by TypedEnum.h and TypedEnumBits.h. */
    1.11 +
    1.12 +// NOTE: When we can assume C++11 enum class support and TypedEnum.h goes away,
    1.13 +// we should then consider folding TypedEnumInternal.h into TypedEnumBits.h.
    1.14 +
    1.15 +#ifndef mozilla_TypedEnumInternal_h
    1.16 +#define mozilla_TypedEnumInternal_h
    1.17 +
    1.18 +#include "mozilla/Attributes.h"
    1.19 +
    1.20 +#if defined(__cplusplus)
    1.21 +
    1.22 +#if defined(__clang__)
    1.23 +   /*
    1.24 +    * Per Clang documentation, "Note that marketing version numbers should not
    1.25 +    * be used to check for language features, as different vendors use different
    1.26 +    * numbering schemes. Instead, use the feature checking macros."
    1.27 +    */
    1.28 +#  ifndef __has_extension
    1.29 +#    define __has_extension __has_feature /* compatibility, for older versions of clang */
    1.30 +#  endif
    1.31 +#  if __has_extension(cxx_strong_enums)
    1.32 +#    define MOZ_HAVE_CXX11_ENUM_TYPE
    1.33 +#    define MOZ_HAVE_CXX11_STRONG_ENUMS
    1.34 +#  endif
    1.35 +#elif defined(__GNUC__)
    1.36 +#  if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
    1.37 +#    if MOZ_GCC_VERSION_AT_LEAST(4, 6, 3)
    1.38 +#      define MOZ_HAVE_CXX11_ENUM_TYPE
    1.39 +#      define MOZ_HAVE_CXX11_STRONG_ENUMS
    1.40 +#    endif
    1.41 +#  endif
    1.42 +#elif defined(_MSC_VER)
    1.43 +#  if _MSC_VER >= 1400
    1.44 +#    define MOZ_HAVE_CXX11_ENUM_TYPE
    1.45 +#  endif
    1.46 +#  if _MSC_VER >= 1700
    1.47 +#    define MOZ_HAVE_CXX11_STRONG_ENUMS
    1.48 +#  endif
    1.49 +#endif
    1.50 +
    1.51 +namespace mozilla {
    1.52 +
    1.53 +/*
    1.54 + * The problem that CastableTypedEnumResult aims to solve is that
    1.55 + * typed enums are not convertible to bool, and there is no way to make them
    1.56 + * be, yet user code wants to be able to write
    1.57 + *
    1.58 + *   if (myFlags & Flags::SOME_PARTICULAR_FLAG)              (1)
    1.59 + *
    1.60 + * There are different approaches to solving this. Most of them require
    1.61 + * adapting user code. For example, we could implement operator! and have
    1.62 + * the user write
    1.63 + *
    1.64 + *   if (!!(myFlags & Flags::SOME_PARTICULAR_FLAG))          (2)
    1.65 + *
    1.66 + * Or we could supply a IsNonZero() or Any() function returning whether
    1.67 + * an enum value is nonzero, and have the user write
    1.68 + *
    1.69 + *   if (Any(Flags & Flags::SOME_PARTICULAR_FLAG))           (3)
    1.70 + *
    1.71 + * But instead, we choose to preserve the original user syntax (1) as it
    1.72 + * is inherently more readable, and to ease porting existing code to typed
    1.73 + * enums. We achieve this by having operator& and other binary bitwise
    1.74 + * operators have as return type a class, CastableTypedEnumResult,
    1.75 + * that wraps a typed enum but adds bool convertibility.
    1.76 + */
    1.77 +template<typename E>
    1.78 +class CastableTypedEnumResult
    1.79 +{
    1.80 +  private:
    1.81 +    const E mValue;
    1.82 +
    1.83 +  public:
    1.84 +    explicit MOZ_CONSTEXPR CastableTypedEnumResult(E value)
    1.85 +      : mValue(value)
    1.86 +    {}
    1.87 +
    1.88 +    MOZ_CONSTEXPR operator E() const { return mValue; }
    1.89 +
    1.90 +    template<typename DestinationType>
    1.91 +    MOZ_EXPLICIT_CONVERSION MOZ_CONSTEXPR
    1.92 +    operator DestinationType() const {
    1.93 +      return DestinationType(mValue);
    1.94 +    }
    1.95 +
    1.96 +    MOZ_CONSTEXPR bool operator !() const { return !bool(mValue); }
    1.97 +
    1.98 +#ifndef MOZ_HAVE_CXX11_STRONG_ENUMS
    1.99 +    // This get() method is used to implement a constructor in the
   1.100 +    // non-c++11 fallback path for MOZ_BEGIN_ENUM_CLASS, taking a
   1.101 +    // CastableTypedEnumResult. If we try to implement it using the
   1.102 +    // above conversion operator E(), then at least clang 3.3
   1.103 +    // (when forced to take the non-c++11 fallback path) compiles
   1.104 +    // this constructor to an infinite recursion. So we introduce this
   1.105 +    // get() method, that does exactly the same as the conversion operator,
   1.106 +    // to work around this.
   1.107 +    MOZ_CONSTEXPR E get() const { return mValue; }
   1.108 +#endif
   1.109 +};
   1.110 +
   1.111 +} // namespace mozilla
   1.112 +
   1.113 +#endif // __cplusplus
   1.114 +
   1.115 +#endif // mozilla_TypedEnumInternal_h

mercurial