/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* Iterator over contiguous enum values */ /* * Implements generator functions that create a range to iterate over the values * of a scoped or unscoped enum. Unlike IntegerRange, which can only function on * the underlying integral type, the elements of the generated sequence will * have the type of the enum in question. * * Note that the enum values should be contiguous in the iterated range; * unfortunately there exists no way for EnumeratedRange to enforce this * either dynamically or at compile time. */ #ifndef mozilla_EnumeratedRange_h #define mozilla_EnumeratedRange_h #include #include #include "mozilla/Assertions.h" #include "mozilla/ReverseIterator.h" namespace mozilla { namespace detail { template class EnumeratedIterator { public: typedef typename std::underlying_type::type IntTypeT; template constexpr explicit EnumeratedIterator(EnumType aCurrent) : mCurrent(aCurrent) {} template explicit EnumeratedIterator(const EnumeratedIterator& aOther) : mCurrent(aOther.mCurrent) {} EnumTypeT operator*() const { return mCurrent; } /* Increment and decrement operators */ EnumeratedIterator& operator++() { mCurrent = EnumTypeT(IntTypeT(mCurrent) + IntTypeT(1)); return *this; } EnumeratedIterator& operator--() { mCurrent = EnumTypeT(IntTypeT(mCurrent) - IntTypeT(1)); return *this; } EnumeratedIterator operator++(int) { auto ret = *this; mCurrent = EnumTypeT(IntTypeT(mCurrent) + IntTypeT(1)); return ret; } EnumeratedIterator operator--(int) { auto ret = *this; mCurrent = EnumTypeT(IntTypeT(mCurrent) - IntTypeT(1)); return ret; } /* Comparison operators */ template friend bool operator==(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2); template friend bool operator!=(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2); template friend bool operator<(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2); template friend bool operator<=(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2); template friend bool operator>(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2); template friend bool operator>=(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2); private: EnumTypeT mCurrent; }; template bool operator==(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2) { return aIter1.mCurrent == aIter2.mCurrent; } template bool operator!=(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2) { return aIter1.mCurrent != aIter2.mCurrent; } template bool operator<(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2) { return aIter1.mCurrent < aIter2.mCurrent; } template bool operator<=(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2) { return aIter1.mCurrent <= aIter2.mCurrent; } template bool operator>(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2) { return aIter1.mCurrent > aIter2.mCurrent; } template bool operator>=(const EnumeratedIterator& aIter1, const EnumeratedIterator& aIter2) { return aIter1.mCurrent >= aIter2.mCurrent; } template class EnumeratedRange { public: typedef EnumeratedIterator iterator; typedef EnumeratedIterator const_iterator; typedef ReverseIterator reverse_iterator; typedef ReverseIterator const_reverse_iterator; template constexpr EnumeratedRange(EnumType aBegin, EnumType aEnd) : mBegin(aBegin), mEnd(aEnd) {} iterator begin() const { return iterator(mBegin); } const_iterator cbegin() const { return begin(); } iterator end() const { return iterator(mEnd); } const_iterator cend() const { return end(); } reverse_iterator rbegin() const { return reverse_iterator(mEnd); } const_reverse_iterator crbegin() const { return rbegin(); } reverse_iterator rend() const { return reverse_iterator(mBegin); } const_reverse_iterator crend() const { return rend(); } private: EnumTypeT mBegin; EnumTypeT mEnd; }; } // namespace detail #ifdef __GNUC__ // Enums can have an unsigned underlying type, which makes some of the // comparisons below always true or always false. Temporarily disable // -Wtype-limits to avoid breaking -Werror builds. # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wtype-limits" #endif // Create a range to iterate from aBegin to aEnd, exclusive. template constexpr detail::EnumeratedRange MakeEnumeratedRange(EnumType aBegin, EnumType aEnd) { MOZ_ASSERT(aBegin <= aEnd, "Cannot generate invalid, unbounded range!"); return detail::EnumeratedRange(aBegin, aEnd); } // Create a range to iterate from EnumType(0) to aEnd, exclusive. EnumType(0) // should exist, but note that there is no way for us to ensure that it does! template constexpr detail::EnumeratedRange MakeEnumeratedRange(EnumType aEnd) { return MakeEnumeratedRange(EnumType(0), aEnd); } // Create a range to iterate from aBegin to aEnd, inclusive. // // NOTE: This internally constructs a value that is one past `aEnd`, so the // enumeration needs to either have a fixed underlying type, or `aEnd + 1` must // be inside the range of the enumeration, in order to not be undefined // behavior. // // See bug 1614512. template constexpr detail::EnumeratedRange MakeInclusiveEnumeratedRange( EnumType aBegin, EnumType aEnd) { using EnumUnderlyingType = typename std::underlying_type_t; const auto end = static_cast(aEnd); MOZ_ASSERT(end != std::numeric_limits::max(), "aEnd shouldn't overflow!"); return MakeEnumeratedRange(aBegin, static_cast(end + 1)); } template constexpr auto MakeInclusiveEnumeratedRange(EnumType aEnd) { return MakeInclusiveEnumeratedRange(EnumType{0}, aEnd); } #ifdef __GNUC__ # pragma GCC diagnostic pop #endif } // namespace mozilla #endif // mozilla_EnumeratedRange_h