tor-browser

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

EnumeratedRange.h (6296B)


      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 /* Iterator over contiguous enum values */
      8 
      9 /*
     10 * Implements generator functions that create a range to iterate over the values
     11 * of a scoped or unscoped enum. Unlike IntegerRange, which can only function on
     12 * the underlying integral type, the elements of the generated sequence will
     13 * have the type of the enum in question.
     14 *
     15 * Note that the enum values should be contiguous in the iterated range;
     16 * unfortunately there exists no way for EnumeratedRange to enforce this
     17 * either dynamically or at compile time.
     18 */
     19 
     20 #ifndef mozilla_EnumeratedRange_h
     21 #define mozilla_EnumeratedRange_h
     22 
     23 #include <limits>
     24 #include <type_traits>
     25 
     26 #include "mozilla/Assertions.h"
     27 #include "mozilla/ReverseIterator.h"
     28 
     29 namespace mozilla {
     30 
     31 namespace detail {
     32 
     33 template <typename EnumTypeT>
     34 class EnumeratedIterator {
     35 public:
     36  typedef std::underlying_type_t<EnumTypeT> IntTypeT;
     37 
     38  template <typename EnumType>
     39  constexpr explicit EnumeratedIterator(EnumType aCurrent)
     40      : mCurrent(aCurrent) {}
     41 
     42  template <typename EnumType>
     43  explicit EnumeratedIterator(const EnumeratedIterator<EnumType>& aOther)
     44      : mCurrent(aOther.mCurrent) {}
     45 
     46  EnumTypeT operator*() const { return mCurrent; }
     47 
     48  /* Increment and decrement operators */
     49 
     50  EnumeratedIterator& operator++() {
     51    mCurrent = EnumTypeT(IntTypeT(mCurrent) + IntTypeT(1));
     52    return *this;
     53  }
     54  EnumeratedIterator& operator--() {
     55    mCurrent = EnumTypeT(IntTypeT(mCurrent) - IntTypeT(1));
     56    return *this;
     57  }
     58  EnumeratedIterator operator++(int) {
     59    auto ret = *this;
     60    mCurrent = EnumTypeT(IntTypeT(mCurrent) + IntTypeT(1));
     61    return ret;
     62  }
     63  EnumeratedIterator operator--(int) {
     64    auto ret = *this;
     65    mCurrent = EnumTypeT(IntTypeT(mCurrent) - IntTypeT(1));
     66    return ret;
     67  }
     68 
     69  /* Comparison operators */
     70 
     71  friend bool operator==(const EnumeratedIterator<EnumTypeT>& aIter1,
     72                         const EnumeratedIterator<EnumTypeT>& aIter2) {
     73    return aIter1.mCurrent == aIter2.mCurrent;
     74  }
     75 
     76  friend bool operator!=(const EnumeratedIterator<EnumTypeT>& aIter1,
     77                         const EnumeratedIterator<EnumTypeT>& aIter2) {
     78    return aIter1.mCurrent != aIter2.mCurrent;
     79  }
     80 
     81  friend bool operator<(const EnumeratedIterator<EnumTypeT>& aIter1,
     82                        const EnumeratedIterator<EnumTypeT>& aIter2) {
     83    return aIter1.mCurrent < aIter2.mCurrent;
     84  }
     85 
     86  friend bool operator<=(const EnumeratedIterator<EnumTypeT>& aIter1,
     87                         const EnumeratedIterator<EnumTypeT>& aIter2) {
     88    return aIter1.mCurrent <= aIter2.mCurrent;
     89  }
     90  friend bool operator>(const EnumeratedIterator<EnumTypeT>& aIter1,
     91                        const EnumeratedIterator<EnumTypeT>& aIter2) {
     92    return aIter1.mCurrent > aIter2.mCurrent;
     93  }
     94  friend bool operator>=(const EnumeratedIterator<EnumTypeT>& aIter1,
     95                         const EnumeratedIterator<EnumTypeT>& aIter2) {
     96    return aIter1.mCurrent >= aIter2.mCurrent;
     97  }
     98 
     99 private:
    100  EnumTypeT mCurrent;
    101 };
    102 
    103 template <typename EnumTypeT>
    104 class EnumeratedRange {
    105 public:
    106  typedef EnumeratedIterator<EnumTypeT> iterator;
    107  typedef EnumeratedIterator<EnumTypeT> const_iterator;
    108  typedef ReverseIterator<iterator> reverse_iterator;
    109  typedef ReverseIterator<const_iterator> const_reverse_iterator;
    110 
    111  template <typename EnumType>
    112  constexpr EnumeratedRange(EnumType aBegin, EnumType aEnd)
    113      : mBegin(aBegin), mEnd(aEnd) {}
    114 
    115  iterator begin() const { return iterator(mBegin); }
    116  const_iterator cbegin() const { return begin(); }
    117  iterator end() const { return iterator(mEnd); }
    118  const_iterator cend() const { return end(); }
    119  reverse_iterator rbegin() const { return reverse_iterator(mEnd); }
    120  const_reverse_iterator crbegin() const { return rbegin(); }
    121  reverse_iterator rend() const { return reverse_iterator(mBegin); }
    122  const_reverse_iterator crend() const { return rend(); }
    123 
    124 private:
    125  EnumTypeT mBegin;
    126  EnumTypeT mEnd;
    127 };
    128 
    129 }  // namespace detail
    130 
    131 #ifdef __GNUC__
    132 // Enums can have an unsigned underlying type, which makes some of the
    133 // comparisons below always true or always false. Temporarily disable
    134 // -Wtype-limits to avoid breaking -Werror builds.
    135 #  pragma GCC diagnostic push
    136 #  pragma GCC diagnostic ignored "-Wtype-limits"
    137 #endif
    138 
    139 // Create a range to iterate from aBegin to aEnd, exclusive.
    140 template <typename EnumType>
    141 constexpr detail::EnumeratedRange<EnumType> MakeEnumeratedRange(EnumType aBegin,
    142                                                                EnumType aEnd) {
    143  MOZ_ASSERT(aBegin <= aEnd, "Cannot generate invalid, unbounded range!");
    144  return detail::EnumeratedRange<EnumType>(aBegin, aEnd);
    145 }
    146 
    147 // Create a range to iterate from EnumType(0) to aEnd, exclusive. EnumType(0)
    148 // should exist, but note that there is no way for us to ensure that it does!
    149 template <typename EnumType>
    150 constexpr detail::EnumeratedRange<EnumType> MakeEnumeratedRange(EnumType aEnd) {
    151  return MakeEnumeratedRange(EnumType(0), aEnd);
    152 }
    153 
    154 // Create a range to iterate from aBegin to aEnd, inclusive.
    155 //
    156 // NOTE: This internally constructs a value that is one past `aEnd`, so the
    157 // enumeration needs to either have a fixed underlying type, or `aEnd + 1` must
    158 // be inside the range of the enumeration, in order to not be undefined
    159 // behavior.
    160 //
    161 // See bug 1614512.
    162 template <typename EnumType>
    163 constexpr detail::EnumeratedRange<EnumType> MakeInclusiveEnumeratedRange(
    164    EnumType aBegin, EnumType aEnd) {
    165  using EnumUnderlyingType = std::underlying_type_t<EnumType>;
    166  const auto end = static_cast<EnumUnderlyingType>(aEnd);
    167 
    168  MOZ_ASSERT(end != std::numeric_limits<EnumUnderlyingType>::max(),
    169             "aEnd shouldn't overflow!");
    170  return MakeEnumeratedRange(aBegin, static_cast<EnumType>(end + 1));
    171 }
    172 
    173 template <typename EnumType>
    174 constexpr auto MakeInclusiveEnumeratedRange(EnumType aEnd) {
    175  return MakeInclusiveEnumeratedRange(EnumType{0}, aEnd);
    176 }
    177 
    178 #ifdef __GNUC__
    179 #  pragma GCC diagnostic pop
    180 #endif
    181 
    182 }  // namespace mozilla
    183 
    184 #endif  // mozilla_EnumeratedRange_h