/* -*- 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 "mozilla/IntegerRange.h" #include "mozilla/IntegerTypeTraits.h" namespace mozilla { namespace detail { template class EnumeratedIterator { public: typedef const EnumTypeT ValueType; typedef typename MakeSigned::Type DifferenceType; template explicit EnumeratedIterator(EnumType aCurrent) : mCurrent(aCurrent) { } template EnumeratedIterator(const EnumeratedIterator& aOther) : mCurrent(aOther.mCurrent) { } // Since operator* is required to return a reference, we return // a reference to our member here. const 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; } EnumeratedIterator operator+(DifferenceType aN) const { return EnumeratedIterator(EnumTypeT(IntTypeT(mCurrent) + aN)); } EnumeratedIterator operator-(DifferenceType aN) const { return EnumeratedIterator(EnumTypeT(IntTypeT(mCurrent) - aN)); } EnumeratedIterator& operator+=(DifferenceType aN) { mCurrent = EnumTypeT(IntTypeT(mCurrent) + aN); return *this; } EnumeratedIterator& operator-=(DifferenceType aN) { mCurrent = EnumTypeT(IntTypeT(mCurrent) - aN); return *this; } /* 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 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 inline detail::EnumeratedRange MakeEnumeratedRange(EnumType aBegin, EnumType aEnd) { typedef typename MakeUnsigned::Type UnsignedType; static_assert(sizeof(IntType) >= sizeof(EnumType), "IntType should be at least as big as EnumType!"); MOZ_ASSERT(aBegin <= aEnd, "Cannot generate invalid, unbounded range!"); MOZ_ASSERT_IF(aBegin < EnumType(0), IsSigned::value); MOZ_ASSERT_IF(aBegin >= EnumType(0) && IsSigned::value, UnsignedType(aEnd) <= UnsignedType(MaxValue::value)); 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 inline detail::EnumeratedRange MakeEnumeratedRange(EnumType aEnd) { return MakeEnumeratedRange(EnumType(0), aEnd); } #ifdef __GNUC__ # pragma GCC diagnostic pop #endif } // namespace mozilla #endif // mozilla_EnumeratedRange_h