Bug 1213517 - optimize for maintenance of constraints (member pointer approach). draft
authorJan-Ivar Bruaroey <jib@mozilla.com>
Mon, 27 Jun 2016 10:03:27 -0400
changeset 388775 3ba1a9ed8871131440c083e89619908bebeb0299
parent 388774 ae00b87697d231279b8c9a1f478e4cbbdebb8ee3
child 388776 a7990ecb80257445e725b9a21b9b5b6aa57f435c
push id23232
push userjbruaroey@mozilla.com
push dateSun, 17 Jul 2016 21:00:46 +0000
bugs1213517
milestone50.0a1
Bug 1213517 - optimize for maintenance of constraints (member pointer approach). MozReview-Commit-ID: 4JYb6QnMtVk
dom/media/webrtc/MediaTrackConstraints.cpp
dom/media/webrtc/MediaTrackConstraints.h
--- a/dom/media/webrtc/MediaTrackConstraints.cpp
+++ b/dom/media/webrtc/MediaTrackConstraints.cpp
@@ -71,49 +71,75 @@ NormalizedConstraintSet::Range<bool>::Fi
     uint32_t denominator = mMergeDenominator & 0xffff;
 
     *mIdeal = !!(counter / denominator);
     mMergeDenominator = 0;
   }
 }
 
 NormalizedConstraintSet::LongRange::LongRange(
-    const dom::OwningLongOrConstrainLongRange& aOther, bool advanced)
-: Range<int32_t>(1 + INT32_MIN, INT32_MAX) // +1 avoids Windows compiler bug
+    LongPtrType aMemberPtr,
+    const char* aName,
+    const dom::OwningLongOrConstrainLongRange& aOther,
+    bool advanced,
+    nsTArray<MemberPtrType>* aList)
+: Range<int32_t>((MemberPtrType)aMemberPtr, aName,
+                 1 + INT32_MIN, INT32_MAX, // +1 avoids Windows compiler bug
+                 aList)
 {
   if (aOther.IsLong()) {
     if (advanced) {
       mMin = mMax = aOther.GetAsLong();
     } else {
       mIdeal.emplace(aOther.GetAsLong());
     }
   } else {
     SetFrom(aOther.GetAsConstrainLongRange());
   }
 }
 
+NormalizedConstraintSet::LongLongRange::LongLongRange(
+    LongLongPtrType aMemberPtr,
+    const char* aName,
+    const long long& aOther,
+    nsTArray<MemberPtrType>* aList)
+: Range<int64_t>((MemberPtrType)aMemberPtr, aName,
+                 1 + INT64_MIN, INT64_MAX, // +1 avoids Windows compiler bug
+                 aList)
+{
+  mIdeal.emplace(aOther);
+}
+
 NormalizedConstraintSet::DoubleRange::DoubleRange(
-    const dom::OwningDoubleOrConstrainDoubleRange& aOther, bool advanced)
-: Range<double>(-std::numeric_limits<double>::infinity(),
-                std::numeric_limits<double>::infinity())
+    DoublePtrType aMemberPtr,
+    const char* aName,
+    const dom::OwningDoubleOrConstrainDoubleRange& aOther, bool advanced,
+    nsTArray<MemberPtrType>* aList)
+: Range<double>((MemberPtrType)aMemberPtr, aName,
+                -std::numeric_limits<double>::infinity(),
+                std::numeric_limits<double>::infinity(), aList)
 {
   if (aOther.IsDouble()) {
     if (advanced) {
       mMin = mMax = aOther.GetAsDouble();
     } else {
       mIdeal.emplace(aOther.GetAsDouble());
     }
   } else {
     SetFrom(aOther.GetAsConstrainDoubleRange());
   }
 }
 
 NormalizedConstraintSet::BooleanRange::BooleanRange(
-    const dom::OwningBooleanOrConstrainBooleanParameters& aOther, bool advanced)
-: Range<bool>(false, true)
+    BooleanPtrType aMemberPtr,
+    const char* aName,
+    const dom::OwningBooleanOrConstrainBooleanParameters& aOther,
+    bool advanced,
+    nsTArray<MemberPtrType>* aList)
+: Range<bool>((MemberPtrType)aMemberPtr, aName, false, true, aList)
 {
   if (aOther.IsBoolean()) {
     if (advanced) {
       mMin = mMax = aOther.GetAsBoolean();
     } else {
       mIdeal.emplace(aOther.GetAsBoolean());
     }
   } else {
@@ -124,18 +150,22 @@ NormalizedConstraintSet::BooleanRange::B
     if (r.mExact.WasPassed()) {
       mMin = r.mExact.Value();
       mMax = r.mExact.Value();
     }
   }
 }
 
 NormalizedConstraintSet::StringRange::StringRange(
+    StringPtrType aMemberPtr,
+    const char* aName,
     const dom::OwningStringOrStringSequenceOrConstrainDOMStringParameters& aOther,
-    bool advanced)
+    bool advanced,
+    nsTArray<MemberPtrType>* aList)
+  : BaseRange((MemberPtrType)aMemberPtr, aName, aList)
 {
   if (aOther.IsString()) {
     if (advanced) {
       mExact.insert(aOther.GetAsString());
     } else {
       mIdeal.insert(aOther.GetAsString());
     }
   } else if (aOther.IsStringSequence()) {
@@ -235,106 +265,62 @@ NormalizedConstraintSet::StringRange::Me
   ValueType unioned;
   set_union(mIdeal.begin(), mIdeal.end(),
             aOther.mIdeal.begin(), aOther.mIdeal.end(),
             std::inserter(unioned, unioned.begin()));
   mIdeal = unioned;
   return true;
 }
 
-NormalizedConstraints::NormalizedConstraints(const dom::MediaTrackConstraints& aOther)
-: NormalizedConstraintSet(aOther, false), mBadConstraint(nullptr)
+NormalizedConstraints::NormalizedConstraints(
+    const dom::MediaTrackConstraints& aOther,
+    nsTArray<MemberPtrType>* aList)
+  : NormalizedConstraintSet(aOther, false, aList)
+  , mBadConstraint(nullptr)
 {
   if (aOther.mAdvanced.WasPassed()) {
     for (auto& entry : aOther.mAdvanced.Value()) {
       mAdvanced.AppendElement(NormalizedConstraintSet(entry, true));
     }
   }
 }
 
 // Merge constructor. Create net constraints out of merging a set of others.
 
 NormalizedConstraints::NormalizedConstraints(
     const nsTArray<const NormalizedConstraints*>& aOthers)
   : NormalizedConstraintSet(*aOthers[0])
   , mBadConstraint(nullptr)
 {
+  // Create a list of member pointers.
+  nsTArray<MemberPtrType> list;
+  NormalizedConstraints dummy(MediaTrackConstraints(), &list);
+
   // Do intersection of all required constraints, and average of ideals.
 
   for (uint32_t i = 1; i < aOthers.Length(); i++) {
-    auto& set = *aOthers[i];
+    auto& other = *aOthers[i];
 
-    if (!mWidth.Merge(set.mWidth)) {
-      mBadConstraint = "width";
-      return;
-    }
-    if (!mHeight.Merge(set.mHeight)) {
-      mBadConstraint = "height";
-      return;
-    }
-    if (!mFrameRate.Merge(set.mFrameRate)) {
-      mBadConstraint = "frameRate";
-      return;
-    }
-    if (!mFacingMode.Merge(set.mFacingMode)) {
-      mBadConstraint = "facingMode";
-      return;
-    }
-    if (mMediaSource != set.mMediaSource) {
-      mBadConstraint = "mediaSource";
-      return;
-    }
-    if (mBrowserWindow != set.mBrowserWindow) {
-      mBadConstraint = "browserWindow";
-      return;
-    }
-    if (!mViewportOffsetX.Merge(set.mViewportOffsetX)) {
-      mBadConstraint = "viewportOffsetX";
-      return;
-    }
-    if (!mViewportOffsetY.Merge(set.mViewportOffsetY)) {
-      mBadConstraint = "viewportOffsetY";
-      return;
-    }
-    if (!mViewportWidth.Merge(set.mViewportWidth)) {
-      mBadConstraint = "viewportWidth";
-      return;
-    }
-    if (!mViewportHeight.Merge(set.mViewportHeight)) {
-      mBadConstraint = "viewportHeight";
-      return;
-    }
-    if (!mEchoCancellation.Merge(set.mEchoCancellation)) {
-      mBadConstraint = "echoCancellation";
-      return;
-    }
-    if (!mMozNoiseSuppression.Merge(set.mMozNoiseSuppression)) {
-      mBadConstraint = "mozNoiseSuppression";
-      return;
-    }
-    if (!mMozAutoGainControl.Merge(set.mMozAutoGainControl)) {
-      mBadConstraint = "mozAutoGainControl";
-      return;
+    for (auto& memberPtr : list) {
+      auto& member = this->*memberPtr;
+      auto& otherMember = other.*memberPtr;
+
+      if (!member.Merge(otherMember)) {
+        mBadConstraint = member.mName;
+        return;
+      }
     }
 
-    for (auto& entry : set.mAdvanced) {
+    for (auto& entry : other.mAdvanced) {
       mAdvanced.AppendElement(entry);
     }
   }
-  mWidth.FinalizeMerge();
-  mHeight.FinalizeMerge();
-  mFrameRate.FinalizeMerge();
-  mFacingMode.FinalizeMerge();
-  mViewportOffsetX.FinalizeMerge();
-  mViewportOffsetY.FinalizeMerge();
-  mViewportWidth.FinalizeMerge();
-  mViewportHeight.FinalizeMerge();
-  mEchoCancellation.FinalizeMerge();
-  mMozNoiseSuppression.FinalizeMerge();
-  mMozAutoGainControl.FinalizeMerge();
+  for (auto& memberPtr : list) {
+    (this->*memberPtr).FinalizeMerge();
+  }
 }
 
 FlattenedConstraints::FlattenedConstraints(const NormalizedConstraints& aOther)
 : NormalizedConstraintSet(aOther)
 {
   for (auto& set : aOther.mAdvanced) {
     // Must only apply compatible i.e. inherently non-overconstraining sets
     // This rule is pretty much why this code is centralized here.
--- a/dom/media/webrtc/MediaTrackConstraints.h
+++ b/dom/media/webrtc/MediaTrackConstraints.h
@@ -31,27 +31,53 @@ static Enum StringToEnum(const EnumValue
     }
   }
   return aDefaultValue;
 }
 
 // Helper classes for orthogonal constraints without interdependencies.
 // Instead of constraining values, constrain the constraints themselves.
 
-struct NormalizedConstraintSet
+class NormalizedConstraintSet
 {
+protected:
+  class BaseRange
+  {
+  protected:
+    typedef BaseRange NormalizedConstraintSet::* MemberPtrType;
+
+    BaseRange(MemberPtrType aMemberPtr, const char* aName,
+              nsTArray<MemberPtrType>* aList) : mName(aName) {
+      if (aList) {
+        aList->AppendElement(aMemberPtr);
+      }
+    }
+    virtual ~BaseRange() {}
+  public:
+    virtual bool Merge(const BaseRange& aOther) = 0;
+    virtual void FinalizeMerge() = 0;
+
+    const char* mName;
+  };
+
+  typedef BaseRange NormalizedConstraintSet::* MemberPtrType;
+
+public:
   template<class ValueType>
-  class Range
+  class Range : public BaseRange
   {
   public:
     ValueType mMin, mMax;
     Maybe<ValueType> mIdeal;
 
-    Range(ValueType aMin, ValueType aMax)
-      : mMin(aMin), mMax(aMax), mMergeDenominator(0) {}
+    Range(MemberPtrType aMemberPtr, const char* aName, ValueType aMin,
+          ValueType aMax, nsTArray<MemberPtrType>* aList)
+      : BaseRange(aMemberPtr, aName, aList)
+      , mMin(aMin), mMax(aMax), mMergeDenominator(0) {}
+    virtual ~Range() {};
 
     template<class ConstrainRange>
     void SetFrom(const ConstrainRange& aOther);
     ValueType Clamp(ValueType n) const { return std::max(mMin, std::min(n, mMax)); }
     ValueType Get(ValueType defaultValue) const {
       return Clamp(mIdeal.valueOr(defaultValue));
     }
     bool Intersects(const Range& aOther) const {
@@ -74,103 +100,166 @@ struct NormalizedConstraintSet
           mMergeDenominator = 1;
         } else {
           *mIdeal += aOther.mIdeal.value();
           mMergeDenominator = std::max(2U, mMergeDenominator + 1);
         }
       }
       return true;
     }
-    void FinalizeMerge()
+    void FinalizeMerge() override
     {
       if (mMergeDenominator) {
         *mIdeal /= mMergeDenominator;
         mMergeDenominator = 0;
       }
     }
   private:
+    bool Merge(const BaseRange& aOther) override {
+      return Merge(static_cast<const Range&>(aOther));
+    }
+
     uint32_t mMergeDenominator;
   };
 
   struct LongRange : public Range<int32_t>
   {
-    LongRange(const dom::OwningLongOrConstrainLongRange& aOther, bool advanced);
+    typedef LongRange NormalizedConstraintSet::* LongPtrType;
+
+    LongRange(LongPtrType aMemberPtr, const char* aName,
+              const dom::OwningLongOrConstrainLongRange& aOther, bool advanced,
+              nsTArray<MemberPtrType>* aList);
+  };
+
+  struct LongLongRange : public Range<int64_t>
+  {
+    typedef LongLongRange NormalizedConstraintSet::* LongLongPtrType;
+
+    LongLongRange(LongLongPtrType aMemberPtr, const char* aName,
+                  const long long& aOther,
+                  nsTArray<MemberPtrType>* aList);
   };
 
   struct DoubleRange : public Range<double>
   {
-    DoubleRange(const dom::OwningDoubleOrConstrainDoubleRange& aOther,
-                bool advanced);
+    typedef DoubleRange NormalizedConstraintSet::* DoublePtrType;
+
+    DoubleRange(DoublePtrType aMemberPtr,
+                const char* aName,
+                const dom::OwningDoubleOrConstrainDoubleRange& aOther,
+                bool advanced,
+                nsTArray<MemberPtrType>* aList);
   };
 
   struct BooleanRange : public Range<bool>
   {
-    BooleanRange(const dom::OwningBooleanOrConstrainBooleanParameters& aOther,
-                 bool advanced);
+    typedef BooleanRange NormalizedConstraintSet::* BooleanPtrType;
+
+    BooleanRange(BooleanPtrType aMemberPtr, const char* aName,
+                 const dom::OwningBooleanOrConstrainBooleanParameters& aOther,
+                 bool advanced,
+                 nsTArray<MemberPtrType>* aList);
+
+    BooleanRange(BooleanPtrType aMemberPtr, const char* aName, const bool& aOther,
+                 nsTArray<MemberPtrType>* aList)
+      : Range<bool>((MemberPtrType)aMemberPtr, aName, false, true, aList) {
+      mIdeal.emplace(aOther);
+    }
   };
 
-  struct StringRange
+  struct StringRange : public BaseRange
   {
     typedef std::set<nsString> ValueType;
     ValueType mExact, mIdeal;
 
-    StringRange(
+    typedef StringRange NormalizedConstraintSet::* StringPtrType;
+
+    StringRange(StringPtrType aMemberPtr,  const char* aName,
         const dom::OwningStringOrStringSequenceOrConstrainDOMStringParameters& aOther,
-        bool advanced);
+        bool advanced,
+        nsTArray<MemberPtrType>* aList);
+
+    StringRange(StringPtrType aMemberPtr, const char* aName,
+                const nsString& aOther, nsTArray<MemberPtrType>* aList)
+      : BaseRange((MemberPtrType)aMemberPtr, aName, aList) {
+      mIdeal.insert(aOther);
+    }
+
+    ~StringRange() {}
 
     void SetFrom(const dom::ConstrainDOMStringParameters& aOther);
     ValueType Clamp(const ValueType& n) const;
     ValueType Get(const ValueType& defaultValue) const {
       return Clamp(mIdeal.size() ? mIdeal : defaultValue);
     }
     bool Intersects(const StringRange& aOther) const;
     void Intersect(const StringRange& aOther);
     bool Merge(const StringRange& aOther);
-    void FinalizeMerge() {}
+    void FinalizeMerge() override {}
+  private:
+    bool Merge(const BaseRange& aOther) override {
+      return Merge(static_cast<const StringRange&>(aOther));
+    }
   };
 
   // All new constraints should be added here whether they use flattening or not
   LongRange mWidth, mHeight;
   DoubleRange mFrameRate;
   StringRange mFacingMode;
-  nsString mMediaSource;
-  long long mBrowserWindow;
-  bool mScrollWithPage;
+  StringRange mMediaSource;
+  LongLongRange mBrowserWindow;
+  BooleanRange mScrollWithPage;
   StringRange mDeviceId;
   LongRange mViewportOffsetX, mViewportOffsetY, mViewportWidth, mViewportHeight;
   BooleanRange mEchoCancellation, mMozNoiseSuppression, mMozAutoGainControl;
-
+private:
+  typedef NormalizedConstraintSet T;
+public:
   NormalizedConstraintSet(const dom::MediaTrackConstraintSet& aOther,
-                          bool advanced)
-  : mWidth(aOther.mWidth, advanced)
-  , mHeight(aOther.mHeight, advanced)
-  , mFrameRate(aOther.mFrameRate, advanced)
-  , mFacingMode(aOther.mFacingMode, advanced)
-  , mMediaSource(aOther.mMediaSource)
-  , mBrowserWindow(aOther.mBrowserWindow.WasPassed() ?
-                   aOther.mBrowserWindow.Value() : 0)
-  , mScrollWithPage(aOther.mScrollWithPage.WasPassed() ?
-                    aOther.mScrollWithPage.Value() : false)
-  , mDeviceId(aOther.mDeviceId, advanced)
-  , mViewportOffsetX(aOther.mViewportOffsetX, advanced)
-  , mViewportOffsetY(aOther.mViewportOffsetY, advanced)
-  , mViewportWidth(aOther.mViewportWidth, advanced)
-  , mViewportHeight(aOther.mViewportHeight, advanced)
-  , mEchoCancellation(aOther.mEchoCancellation, advanced)
-  , mMozNoiseSuppression(aOther.mMozNoiseSuppression, advanced)
-  , mMozAutoGainControl(aOther.mMozAutoGainControl, advanced) {}
+                          bool advanced,
+                          nsTArray<MemberPtrType>* aList = nullptr)
+  : mWidth(&T::mWidth, "width", aOther.mWidth, advanced, aList)
+  , mHeight(&T::mHeight, "height", aOther.mHeight, advanced, aList)
+  , mFrameRate(&T::mFrameRate, "frameRate", aOther.mFrameRate, advanced, aList)
+  , mFacingMode(&T::mFacingMode, "facingMode", aOther.mFacingMode, advanced, aList)
+  , mMediaSource(&T::mMediaSource, "mediaSource", aOther.mMediaSource, aList)
+  , mBrowserWindow(&T::mBrowserWindow, "browserWindow",
+                   aOther.mBrowserWindow.WasPassed() ?
+                   aOther.mBrowserWindow.Value() : 0, aList)
+  , mScrollWithPage(&T::mScrollWithPage, "scrollWithPage",
+                    aOther.mScrollWithPage.WasPassed() ?
+                    aOther.mScrollWithPage.Value() : false, aList)
+  , mDeviceId(&T::mDeviceId, "deviceId", aOther.mDeviceId, advanced, aList)
+  , mViewportOffsetX(&T::mViewportOffsetX, "viewportOffsetX",
+                     aOther.mViewportOffsetX, advanced, aList)
+  , mViewportOffsetY(&T::mViewportOffsetY, "viewportOffsetY",
+                     aOther.mViewportOffsetY, advanced, aList)
+  , mViewportWidth(&T::mViewportWidth, "viewportWidth",
+                   aOther.mViewportWidth, advanced, aList)
+  , mViewportHeight(&T::mViewportHeight, "viewportHeight",
+                    aOther.mViewportHeight, advanced, aList)
+  , mEchoCancellation(&T::mEchoCancellation, "echoCancellation",
+                      aOther.mEchoCancellation, advanced, aList)
+  , mMozNoiseSuppression(&T::mMozNoiseSuppression, "mozNoiseSuppression",
+                         aOther.mMozNoiseSuppression,
+                         advanced, aList)
+  , mMozAutoGainControl(&T::mMozAutoGainControl, "mozAutoGainControl",
+                        aOther.mMozAutoGainControl, advanced, aList) {}
 };
 
 template<> bool NormalizedConstraintSet::Range<bool>::Merge(const Range& aOther);
 template<> void NormalizedConstraintSet::Range<bool>::FinalizeMerge();
 
 // Used instead of MediaTrackConstraints in lower-level code.
 struct NormalizedConstraints : public NormalizedConstraintSet
 {
-  explicit NormalizedConstraints(const dom::MediaTrackConstraints& aOther);
+  explicit NormalizedConstraints(const dom::MediaTrackConstraints& aOther,
+                                 nsTArray<MemberPtrType>* aList = nullptr);
+
+  // Merge constructor
   explicit NormalizedConstraints(
       const nsTArray<const NormalizedConstraints*>& aOthers);
 
   nsTArray<NormalizedConstraintSet> mAdvanced;
   const char* mBadConstraint;
 };
 
 // Flattened version is used in low-level code with orthogonal constraints only.