[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[tor-commits] [tor-browser/tor-browser-60.4.0esr-8.5-1] Bug 1474659 Part 1 - Add support to EnumSet for more than 32 values. r?sfink



commit f1381907e4a9a586e38c322dcb8f1bd02315d691
Author: Matt Howell <mhowell@xxxxxxxxxxx>
Date:   Tue Jan 8 09:00:20 2019 +0000

    Bug 1474659 Part 1 - Add support to EnumSet for more than 32 values. r?sfink
    
    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.
---
 mfbt/EnumSet.h             |  55 +++++++++++----------
 mfbt/tests/TestEnumSet.cpp | 121 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 151 insertions(+), 25 deletions(-)

diff --git a/mfbt/EnumSet.h b/mfbt/EnumSet.h
index d8c8a2af8b25..2e17a8f55186 100644
--- a/mfbt/EnumSet.h
+++ b/mfbt/EnumSet.h
@@ -13,21 +13,26 @@
 #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)
@@ -84,9 +89,9 @@ public:
   /**
    * 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;
   }
@@ -94,7 +99,7 @@ public:
   /**
    * Union
    */
-  void operator+=(const EnumSet<T> aEnumSet)
+  void operator+=(const EnumSet<T,U> aEnumSet)
   {
     incVersion();
     mBitField |= aEnumSet.mBitField;
@@ -103,9 +108,9 @@ public:
   /**
    * 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;
   }
@@ -122,9 +127,9 @@ public:
   /**
    * 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;
   }
@@ -132,7 +137,7 @@ public:
   /**
    * Remove a set of elements
    */
-  void operator-=(const EnumSet<T> aEnumSet)
+  void operator-=(const EnumSet<T,U> aEnumSet)
   {
     incVersion();
     mBitField &= ~(aEnumSet.mBitField);
@@ -141,9 +146,9 @@ public:
   /**
    * 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;
   }
@@ -160,7 +165,7 @@ public:
   /**
    * Intersection
    */
-  void operator&=(const EnumSet<T> aEnumSet)
+  void operator&=(const EnumSet<T,U> aEnumSet)
   {
     incVersion();
     mBitField &= aEnumSet.mBitField;
@@ -169,9 +174,9 @@ public:
   /**
    * 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;
   }
@@ -179,7 +184,7 @@ public:
   /**
    * Equality
    */
-  bool operator==(const EnumSet<T> aEnumSet) const
+  bool operator==(const EnumSet<T,U> aEnumSet) const
   {
     return mBitField == aEnumSet.mBitField;
   }
@@ -198,7 +203,7 @@ public:
   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++;
       }
@@ -224,7 +229,7 @@ public:
 
   class ConstIterator
   {
-    const EnumSet<T>* mSet;
+    const EnumSet<T,U>* mSet;
     uint32_t mPos;
 #ifdef DEBUG
     uint64_t mVersion;
@@ -236,7 +241,7 @@ public:
     }
 
    public:
-    ConstIterator(const EnumSet<T>& aSet, uint32_t aPos)
+    ConstIterator(const EnumSet<T,U>& aSet, uint32_t aPos)
      : mSet(&aSet), mPos(aPos)
     {
 #ifdef DEBUG
@@ -308,11 +313,11 @@ public:
   }
 
 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() {
@@ -321,7 +326,7 @@ private:
 #endif
   }
 
-  static const size_t kMaxBits = 32;
+  static const size_t kMaxBits = std::numeric_limits<serializedType>::digits;
   serializedType mBitField;
 
 #ifdef DEBUG
diff --git a/mfbt/tests/TestEnumSet.cpp b/mfbt/tests/TestEnumSet.cpp
index 801295fd67dc..903b74c5b834 100644
--- a/mfbt/tests/TestEnumSet.cpp
+++ b/mfbt/tests/TestEnumSet.cpp
@@ -33,6 +33,65 @@ enum SeaBird
   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:
@@ -62,6 +121,8 @@ public:
     testDuplicates();
     testIteration();
     testInitializerListConstuctor();
+    testLargeEnum();
+    testSmallEnum();
   }
 
 private:
@@ -273,6 +334,66 @@ private:
     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;



_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits