Bug 1052582 Part 1 - Add support to EnumSet for more than 32 values. r?Waldo
The next patch in this series extends an enum that's used in an EnumSet to 34
values, so we need to extend EnumSet beyond a hardcoded uint32_t storage type.
MozReview-Commit-ID: J3Pxj5xYtdb
--- a/mfbt/EnumSet.h
+++ b/mfbt/EnumSet.h
@@ -8,31 +8,36 @@
#ifndef mozilla_EnumSet_h
#define mozilla_EnumSet_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include <initializer_list>
+#include <limits>
#include <stdint.h>
namespace mozilla {
/**
- * EnumSet<T> is a set of values defined by an enumeration. It is implemented
- * using a 32 bit mask for each value so it will only work for enums with an int
- * representation less than 32. It works both for enum and enum class types.
+ * EnumSet represents a set of multiple values of an enum (or enum class).
+ * Template parameter T should be the enum you want to represent.
+ * EnumSet is implemented using a bitmask of all possible values of the enum T,
+ * and the default type for the bitmask value is uint32_t, so if your enum has
+ * more than 32 possible values, you should also supply a backing integer type
+ * as template parameter U which has at least as many bits as the number of
+ * possible values of enum T.
*/
-template<typename T>
+template<typename T, typename U = uint32_t>
class EnumSet
{
public:
- typedef uint32_t serializedType;
+ typedef U serializedType;
EnumSet()
: mBitField(0)
{
}
MOZ_IMPLICIT EnumSet(T aEnum)
: mBitField(bitFor(aEnum))
@@ -79,112 +84,112 @@ public:
{
incVersion();
mBitField |= bitFor(aEnum);
}
/**
* Add an element
*/
- EnumSet<T> operator+(T aEnum) const
+ EnumSet<T,U> operator+(T aEnum) const
{
- EnumSet<T> result(*this);
+ EnumSet<T,U> result(*this);
result += aEnum;
return result;
}
/**
* Union
*/
- void operator+=(const EnumSet<T> aEnumSet)
+ void operator+=(const EnumSet<T,U> aEnumSet)
{
incVersion();
mBitField |= aEnumSet.mBitField;
}
/**
* Union
*/
- EnumSet<T> operator+(const EnumSet<T> aEnumSet) const
+ EnumSet<T,U> operator+(const EnumSet<T,U> aEnumSet) const
{
- EnumSet<T> result(*this);
+ EnumSet<T,U> result(*this);
result += aEnumSet;
return result;
}
/**
* Remove an element
*/
void operator-=(T aEnum)
{
incVersion();
mBitField &= ~(bitFor(aEnum));
}
/**
* Remove an element
*/
- EnumSet<T> operator-(T aEnum) const
+ EnumSet<T,U> operator-(T aEnum) const
{
- EnumSet<T> result(*this);
+ EnumSet<T,U> result(*this);
result -= aEnum;
return result;
}
/**
* Remove a set of elements
*/
- void operator-=(const EnumSet<T> aEnumSet)
+ void operator-=(const EnumSet<T,U> aEnumSet)
{
incVersion();
mBitField &= ~(aEnumSet.mBitField);
}
/**
* Remove a set of elements
*/
- EnumSet<T> operator-(const EnumSet<T> aEnumSet) const
+ EnumSet<T,U> operator-(const EnumSet<T,U> aEnumSet) const
{
- EnumSet<T> result(*this);
+ EnumSet<T,U> result(*this);
result -= aEnumSet;
return result;
}
/**
* Clear
*/
void clear()
{
incVersion();
mBitField = 0;
}
/**
* Intersection
*/
- void operator&=(const EnumSet<T> aEnumSet)
+ void operator&=(const EnumSet<T,U> aEnumSet)
{
incVersion();
mBitField &= aEnumSet.mBitField;
}
/**
* Intersection
*/
- EnumSet<T> operator&(const EnumSet<T> aEnumSet) const
+ EnumSet<T,U> operator&(const EnumSet<T,U> aEnumSet) const
{
- EnumSet<T> result(*this);
+ EnumSet<T,U> result(*this);
result &= aEnumSet;
return result;
}
/**
* Equality
*/
- bool operator==(const EnumSet<T> aEnumSet) const
+ bool operator==(const EnumSet<T,U> aEnumSet) const
{
return mBitField == aEnumSet.mBitField;
}
/**
* Test is an element is contained in the set.
*/
bool contains(T aEnum) const
@@ -193,17 +198,17 @@ public:
}
/**
* Return the number of elements in the set.
*/
uint8_t size() const
{
uint8_t count = 0;
- for (uint32_t bitField = mBitField; bitField; bitField >>= 1) {
+ for (serializedType bitField = mBitField; bitField; bitField >>= 1) {
if (bitField & 1) {
count++;
}
}
return count;
}
bool isEmpty() const
@@ -219,29 +224,29 @@ public:
void deserialize(serializedType aValue)
{
incVersion();
mBitField = aValue;
}
class ConstIterator
{
- const EnumSet<T>* mSet;
+ const EnumSet<T,U>* mSet;
uint32_t mPos;
#ifdef DEBUG
uint64_t mVersion;
#endif
void checkVersion() const {
// Check that the set has not been modified while being iterated.
MOZ_ASSERT_IF(mSet, mSet->mVersion == mVersion);
}
public:
- ConstIterator(const EnumSet<T>& aSet, uint32_t aPos)
+ ConstIterator(const EnumSet<T,U>& aSet, uint32_t aPos)
: mSet(&aSet), mPos(aPos)
{
#ifdef DEBUG
mVersion = mSet->mVersion;
#endif
MOZ_ASSERT(aPos <= kMaxBits);
if (aPos != kMaxBits && !mSet->contains(T(mPos)))
++*this;
@@ -303,30 +308,30 @@ public:
return ConstIterator(*this, 0);
}
ConstIterator end() const {
return ConstIterator(*this, kMaxBits);
}
private:
- static uint32_t bitFor(T aEnum)
+ static serializedType bitFor(T aEnum)
{
uint32_t bitNumber = (uint32_t)aEnum;
MOZ_ASSERT(bitNumber < kMaxBits);
- return 1U << bitNumber;
+ return (serializedType)1 << bitNumber;
}
void incVersion() {
#ifdef DEBUG
mVersion++;
#endif
}
- static const size_t kMaxBits = 32;
+ static const size_t kMaxBits = std::numeric_limits<serializedType>::digits;
serializedType mBitField;
#ifdef DEBUG
uint64_t mVersion = 0;
#endif
};
} // namespace mozilla
--- a/mfbt/tests/TestEnumSet.cpp
+++ b/mfbt/tests/TestEnumSet.cpp
@@ -28,16 +28,75 @@ enum SeaBird
TROPICBIRD,
SKUA,
GULL,
TERN,
SKIMMER,
AUK
};
+enum DeepSeaFish
+{
+ FLATFISH,
+ HAGFISH,
+ EELPOUT,
+ GREENEYE_EEL,
+ STRINGRAY,
+ LUMPFISH,
+ BATFISH,
+ RATTAIL,
+ BROTULA,
+ BRISTLEMOUTH,
+ ANGLERFISH,
+ FANGTOOTH,
+ VIPERFISH,
+ BLACK_SWALLOWER,
+ TELESCOPEFISH,
+ HAMMERJAW,
+ DAGGERTOOTH,
+ BARRACUDINA,
+ SCABBARDFISH,
+ BOBTAIL_SNIPE_EEL,
+ UNICORN_CRESTFISH,
+ PELICAN_EEL,
+ FLABBY_WHALEFISH,
+ LANTERNFISH,
+ OPAH,
+ LANCEFISH,
+ BARRELEYE,
+ RIDGEHEAD,
+ SABRETOOTH,
+ STOPLIGHT_LOOSEJAW,
+ HATCHETFISH,
+ DOLPHINFISH,
+ POMFRET,
+ BARRACUDA,
+ SNAGGLETOOTH,
+ BLACKSMELT,
+ TAPIRFISH,
+ GRENADIER,
+ SLICKHEAD,
+ OREODORY,
+ SPIDERFISH,
+};
+
+enum Mollusc
+{
+ SNAIL,
+ SLUG,
+ CLAM,
+ OYSTER,
+ SCALLOP,
+ GEODUCK,
+ MUSSEL,
+ SQUID,
+ OCTOPUS,
+ CUTTLEFISH
+};
+
class EnumSetSuite
{
public:
EnumSetSuite()
: mAlcidae()
, mDiomedeidae(ALBATROSS)
, mPetrelProcellariidae(GADFLY_PETREL, TRUE_PETREL)
, mNonPetrelProcellariidae(FULMAR, PRION, SHEARWATER)
@@ -57,16 +116,18 @@ public:
testRemoveAllFrom();
testRemoveAll();
testIntersect();
testInsersection();
testEquality();
testDuplicates();
testIteration();
testInitializerListConstuctor();
+ testLargeEnum();
+ testSmallEnum();
}
private:
void testSize()
{
MOZ_RELEASE_ASSERT(mAlcidae.size() == 0);
MOZ_RELEASE_ASSERT(mDiomedeidae.size() == 1);
MOZ_RELEASE_ASSERT(mPetrelProcellariidae.size() == 2);
@@ -268,16 +329,76 @@ private:
EnumSet<SeaBird> someBirds { SKIMMER, GULL, BOOBY };
MOZ_RELEASE_ASSERT(someBirds.size() == 3);
MOZ_RELEASE_ASSERT(someBirds.contains(SKIMMER));
MOZ_RELEASE_ASSERT(someBirds.contains(GULL));
MOZ_RELEASE_ASSERT(someBirds.contains(BOOBY));
}
+ void testLargeEnum()
+ {
+ typedef EnumSet<DeepSeaFish, uint64_t> FishSet;
+ FishSet fishes {};
+ MOZ_RELEASE_ASSERT(fishes.size() == 0);
+ MOZ_RELEASE_ASSERT(fishes.isEmpty());
+
+ fishes += ANGLERFISH;
+ fishes += SPIDERFISH;
+ fishes += GRENADIER;
+ fishes += FLATFISH;
+
+ MOZ_RELEASE_ASSERT(fishes.size() == 4);
+ MOZ_RELEASE_ASSERT(fishes.contains(ANGLERFISH));
+ MOZ_RELEASE_ASSERT(fishes.contains(SPIDERFISH));
+ MOZ_RELEASE_ASSERT(fishes.contains(GRENADIER));
+ MOZ_RELEASE_ASSERT(fishes.contains(FLATFISH));
+
+ Vector<DeepSeaFish> vec;
+ for (auto fish : fishes) {
+ MOZ_RELEASE_ASSERT(vec.append(fish));
+ }
+
+ MOZ_RELEASE_ASSERT(vec.length() == 4);
+ MOZ_RELEASE_ASSERT(vec[0] == FLATFISH);
+ MOZ_RELEASE_ASSERT(vec[1] == ANGLERFISH);
+ MOZ_RELEASE_ASSERT(vec[2] == GRENADIER);
+ MOZ_RELEASE_ASSERT(vec[3] == SPIDERFISH);
+ }
+
+ void testSmallEnum()
+ {
+ typedef EnumSet<Mollusc, uint16_t> MolluscSet;
+ MolluscSet molluscs {};
+ MOZ_RELEASE_ASSERT(molluscs.size() == 0);
+ MOZ_RELEASE_ASSERT(molluscs.isEmpty());
+
+ molluscs += OYSTER;
+ molluscs += SQUID;
+ molluscs += SNAIL;
+ molluscs += CUTTLEFISH;
+
+ MOZ_RELEASE_ASSERT(molluscs.size() == 4);
+ MOZ_RELEASE_ASSERT(molluscs.contains(OYSTER));
+ MOZ_RELEASE_ASSERT(molluscs.contains(SQUID));
+ MOZ_RELEASE_ASSERT(molluscs.contains(SNAIL));
+ MOZ_RELEASE_ASSERT(molluscs.contains(CUTTLEFISH));
+
+ Vector<Mollusc> vec;
+ for (auto mollusc : molluscs) {
+ MOZ_RELEASE_ASSERT(vec.append(mollusc));
+ }
+
+ MOZ_RELEASE_ASSERT(vec.length() == 4);
+ MOZ_RELEASE_ASSERT(vec[0] == SNAIL);
+ MOZ_RELEASE_ASSERT(vec[1] == OYSTER);
+ MOZ_RELEASE_ASSERT(vec[2] == SQUID);
+ MOZ_RELEASE_ASSERT(vec[3] == CUTTLEFISH);
+ }
+
EnumSet<SeaBird> mAlcidae;
EnumSet<SeaBird> mDiomedeidae;
EnumSet<SeaBird> mPetrelProcellariidae;
EnumSet<SeaBird> mNonPetrelProcellariidae;
EnumSet<SeaBird> mPetrels;
};
int