tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TypedEnumBits.h (5842B)


      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/. */
      6 
      7 /*
      8 * MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS allows using a typed enum as bit flags.
      9 */
     10 
     11 #ifndef mozilla_TypedEnumBits_h
     12 #define mozilla_TypedEnumBits_h
     13 
     14 #include "mozilla/IntegerTypeTraits.h"
     15 
     16 namespace mozilla {
     17 
     18 /*
     19 * The problem that CastableTypedEnumResult aims to solve is that
     20 * typed enums are not convertible to bool, and there is no way to make them
     21 * be, yet user code wants to be able to write
     22 *
     23 *   if (myFlags & Flags::SOME_PARTICULAR_FLAG)              (1)
     24 *
     25 * There are different approaches to solving this. Most of them require
     26 * adapting user code. For example, we could implement operator! and have
     27 * the user write
     28 *
     29 *   if (!!(myFlags & Flags::SOME_PARTICULAR_FLAG))          (2)
     30 *
     31 * Or we could supply a IsNonZero() or Any() function returning whether
     32 * an enum value is nonzero, and have the user write
     33 *
     34 *   if (Any(Flags & Flags::SOME_PARTICULAR_FLAG))           (3)
     35 *
     36 * But instead, we choose to preserve the original user syntax (1) as it
     37 * is inherently more readable, and to ease porting existing code to typed
     38 * enums. We achieve this by having operator& and other binary bitwise
     39 * operators have as return type a class, CastableTypedEnumResult,
     40 * that wraps a typed enum but adds bool convertibility.
     41 */
     42 template <typename E>
     43 class CastableTypedEnumResult {
     44 private:
     45  const E mValue;
     46 
     47 public:
     48  explicit constexpr CastableTypedEnumResult(E aValue) : mValue(aValue) {}
     49 
     50  constexpr operator E() const { return mValue; }
     51 
     52  template <typename DestinationType>
     53  explicit constexpr operator DestinationType() const {
     54    return DestinationType(mValue);
     55  }
     56 
     57  constexpr bool operator!() const { return !bool(mValue); }
     58 };
     59 
     60 #define MOZ_CASTABLETYPEDENUMRESULT_BINOP(Op, OtherType, ReturnType)        \
     61  template <typename E>                                                     \
     62  constexpr ReturnType operator Op(const OtherType& aE,                     \
     63                                   const CastableTypedEnumResult<E>& aR) {  \
     64    return ReturnType(aE Op OtherType(aR));                                 \
     65  }                                                                         \
     66  template <typename E>                                                     \
     67  constexpr ReturnType operator Op(const CastableTypedEnumResult<E>& aR,    \
     68                                   const OtherType& aE) {                   \
     69    return ReturnType(OtherType(aR) Op aE);                                 \
     70  }                                                                         \
     71  template <typename E>                                                     \
     72  constexpr ReturnType operator Op(const CastableTypedEnumResult<E>& aR1,   \
     73                                   const CastableTypedEnumResult<E>& aR2) { \
     74    return ReturnType(OtherType(aR1) Op OtherType(aR2));                    \
     75  }
     76 
     77 MOZ_CASTABLETYPEDENUMRESULT_BINOP(|, E, CastableTypedEnumResult<E>)
     78 MOZ_CASTABLETYPEDENUMRESULT_BINOP(&, E, CastableTypedEnumResult<E>)
     79 MOZ_CASTABLETYPEDENUMRESULT_BINOP(^, E, CastableTypedEnumResult<E>)
     80 MOZ_CASTABLETYPEDENUMRESULT_BINOP(==, E, bool)
     81 MOZ_CASTABLETYPEDENUMRESULT_BINOP(!=, E, bool)
     82 
     83 template <typename E>
     84 constexpr CastableTypedEnumResult<E> operator~(
     85    const CastableTypedEnumResult<E>& aR) {
     86  return CastableTypedEnumResult<E>(~(E(aR)));
     87 }
     88 
     89 #define MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(Op)         \
     90  template <typename E>                                            \
     91  E& operator Op(E & aR1, const CastableTypedEnumResult<E>& aR2) { \
     92    return aR1 Op E(aR2);                                          \
     93  }
     94 
     95 MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(&=)
     96 MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(|=)
     97 MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(^=)
     98 
     99 #undef MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP
    100 
    101 #undef MOZ_CASTABLETYPEDENUMRESULT_BINOP
    102 
    103 namespace detail {
    104 template <typename E>
    105 struct UnsignedIntegerTypeForEnum : UnsignedStdintTypeForSize<sizeof(E)> {};
    106 }  // namespace detail
    107 
    108 }  // namespace mozilla
    109 
    110 #define MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, Op)                       \
    111  inline constexpr mozilla::CastableTypedEnumResult<Name> operator Op( \
    112      Name a, Name b) {                                                \
    113    typedef mozilla::CastableTypedEnumResult<Name> Result;             \
    114    typedef mozilla::detail::UnsignedIntegerTypeForEnum<Name>::Type U; \
    115    return Result(Name(U(a) Op U(b)));                                 \
    116  }                                                                    \
    117                                                                       \
    118  inline Name& operator Op##=(Name & a, Name b) { return a = a Op b; }
    119 
    120 /**
    121 * MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS generates standard bitwise operators
    122 * for the given enum type. Use this to enable using an enum type as bit-field.
    123 */
    124 #define MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Name)                           \
    125  MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, |)                                     \
    126  MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, &)                                     \
    127  MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, ^)                                     \
    128  inline constexpr mozilla::CastableTypedEnumResult<Name> operator~(Name a) { \
    129    typedef mozilla::CastableTypedEnumResult<Name> Result;                    \
    130    typedef mozilla::detail::UnsignedIntegerTypeForEnum<Name>::Type U;        \
    131    return Result(Name(~(U(a))));                                             \
    132  }
    133 
    134 #endif  // mozilla_TypedEnumBits_h