LCOV - code coverage report
Current view: top level - dom/base - OrderedTimeoutIterator.h (source / functions) Hit Total Coverage
Test: output.info Lines: 30 61 49.2 %
Date: 2017-07-14 16:53:18 Functions: 4 6 66.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef mozilla_dom_OrderedTimeoutIterator_h__
       8             : #define mozilla_dom_OrderedTimeoutIterator_h__
       9             : 
      10             : #include "mozilla/RefPtr.h"
      11             : #include "mozilla/dom/Timeout.h"
      12             : #include "mozilla/dom/TimeoutManager.h"
      13             : 
      14             : namespace mozilla {
      15             : namespace dom {
      16             : 
      17             : // This class implements and iterator which iterates the normal and tracking
      18             : // timeouts lists simultaneously in the mWhen order.
      19          16 : class MOZ_STACK_CLASS OrderedTimeoutIterator final {
      20             : public:
      21             :   typedef TimeoutManager::Timeouts Timeouts;
      22             :   typedef Timeouts::TimeoutList    TimeoutList;
      23             : 
      24          16 :   OrderedTimeoutIterator(Timeouts& aNormalTimeouts,
      25             :                          Timeouts& aTrackingTimeouts)
      26          16 :     : mNormalTimeouts(aNormalTimeouts.mTimeoutList),
      27             :       mTrackingTimeouts(aTrackingTimeouts.mTimeoutList),
      28          16 :       mNormalIter(mNormalTimeouts.getFirst()),
      29          16 :       mTrackingIter(mTrackingTimeouts.getFirst()),
      30             :       mKind(Kind::None),
      31          48 :       mUpdateIteratorCalled(true)
      32             :   {
      33          16 :   }
      34             : 
      35             :   // Return the current timeout and move to the next one.
      36             :   // Unless this is the first time calling Next(), you must call
      37             :   // UpdateIterator() before calling this method.
      38          37 :   Timeout* Next()
      39             :   {
      40          37 :     MOZ_ASSERT(mUpdateIteratorCalled);
      41          37 :     MOZ_ASSERT_IF(mNormalIter, mNormalIter->isInList());
      42          37 :     MOZ_ASSERT_IF(mTrackingIter, mTrackingIter->isInList());
      43             : 
      44          37 :     mUpdateIteratorCalled = false;
      45          37 :     mKind = Kind::None;
      46          37 :     Timeout* timeout = nullptr;
      47          37 :     if (!mNormalIter) {
      48           0 :       if (!mTrackingIter) {
      49             :         // We have reached the end of both lists.  Bail out!
      50           0 :         return nullptr;
      51             :       } else {
      52             :         // We have reached the end of the normal timeout list, select the next
      53             :         // tracking timeout.
      54           0 :         timeout = mTrackingIter;
      55           0 :         mKind = Kind::Tracking;
      56             :       }
      57          37 :     } else if (!mTrackingIter) {
      58             :       // We have reached the end of the tracking timeout list, select the next
      59             :       // normal timeout.
      60          37 :       timeout = mNormalIter;
      61          37 :       mKind = Kind::Normal;
      62             :     } else {
      63             :       // If we have a normal and a tracking timer, return the one with the
      64             :       // smaller mWhen (and prefer the timeout with a lower ID in case they are
      65             :       // equal.) Otherwise, return whichever iterator has an item left,
      66             :       // preferring a non-tracking timeout again.  Note that in practice, even
      67             :       // if a web page calls setTimeout() twice in a row, it should get
      68             :       // different mWhen values, so in practice we shouldn't fall back to
      69             :       // comparing timeout IDs.
      70           0 :       if (mNormalIter && mTrackingIter &&
      71           0 :           (mTrackingIter->When() < mNormalIter->When() ||
      72           0 :            (mTrackingIter->When() == mNormalIter->When() &&
      73           0 :             mTrackingIter->mTimeoutId < mNormalIter->mTimeoutId))) {
      74           0 :         timeout = mTrackingIter;
      75           0 :         mKind = Kind::Tracking;
      76           0 :       } else if (mNormalIter) {
      77           0 :         timeout = mNormalIter;
      78           0 :         mKind = Kind::Normal;
      79           0 :       } else if (mTrackingIter) {
      80           0 :         timeout = mTrackingIter;
      81           0 :         mKind = Kind::Tracking;
      82             :       }
      83             :     }
      84          37 :     if (!timeout) {
      85             :       // We didn't find any suitable iterator.  This can happen for example
      86             :       // when getNext() in UpdateIterator() returns nullptr and then Next()
      87             :       // gets called.  Bail out!
      88           0 :       return nullptr;
      89             :     }
      90             : 
      91          37 :     MOZ_ASSERT(mKind != Kind::None);
      92             : 
      93             :     // Record the current timeout we just found.
      94          37 :     mCurrent = timeout;
      95          37 :     MOZ_ASSERT(mCurrent);
      96             : 
      97          37 :     return mCurrent;
      98             :   }
      99             : 
     100             :   // Prepare the iterator for the next call to Next().
     101             :   // This method can be called as many times as needed.  Calling this more than
     102             :   // once is helpful in cases where we expect the timeouts list has been
     103             :   // modified before we got a chance to call Next().
     104          32 :   void UpdateIterator()
     105             :   {
     106          32 :     MOZ_ASSERT(mKind != Kind::None);
     107             :     // Update the winning iterator to point to the next element.  Also check to
     108             :     // see if the other iterator is still valid, otherwise reset it to the
     109             :     // beginning of the list.  This is needed in case a timeout handler removes
     110             :     // the timeout pointed to from one of our iterators.
     111          32 :     if (mKind == Kind::Normal) {
     112          32 :       mNormalIter = mCurrent->getNext();
     113          32 :       if (mTrackingIter && !mTrackingIter->isInList()) {
     114           0 :         mTrackingIter = mTrackingTimeouts.getFirst();
     115             :       }
     116             :     } else {
     117           0 :       mTrackingIter = mCurrent->getNext();
     118           0 :       if (mNormalIter && !mNormalIter->isInList()) {
     119           0 :         mNormalIter = mNormalTimeouts.getFirst();
     120             :       }
     121             :     }
     122             : 
     123          32 :     mUpdateIteratorCalled = true;
     124          32 :   }
     125             : 
     126             :   // This function resets the iterator to a defunct state.  It should only be
     127             :   // used when we want to forcefully sever all of the strong references this
     128             :   // class holds.
     129           0 :   void Clear()
     130             :   {
     131             :     // Release all strong references.
     132           0 :     mNormalIter = nullptr;
     133           0 :     mTrackingIter = nullptr;
     134           0 :     mCurrent = nullptr;
     135           0 :     mKind = Kind::None;
     136           0 :     mUpdateIteratorCalled = true;
     137           0 :   }
     138             : 
     139             :   // Returns true if the previous call to Next() picked a normal timeout.
     140             :   // Cannot be called before Next() has been called.  Note that the result of
     141             :   // this method is only affected by Next() and not UpdateIterator(), so calling
     142             :   // UpdateIterator() before calling this is allowed.
     143             :   bool PickedNormalIter() const
     144             :   {
     145             :     MOZ_ASSERT(mKind != Kind::None);
     146             :     return mKind == Kind::Normal;
     147             :   }
     148             : 
     149             :   // Returns true if the previous call to Next() picked a tracking timeout.
     150             :   // Cannot be called before Next() has been called.  Note that the result of
     151             :   // this method is only affected by Next() and not UpdateIterator(), so calling
     152             :   // UpdateIterator() before calling this is allowed.
     153           0 :   bool PickedTrackingIter() const
     154             :   {
     155           0 :     MOZ_ASSERT(mKind != Kind::None);
     156           0 :     return mKind == Kind::Tracking;
     157             :   }
     158             : 
     159             : private:
     160             :   TimeoutList& mNormalTimeouts;          // The list of normal timeouts.
     161             :   TimeoutList& mTrackingTimeouts;        // The list of tracking timeouts.
     162             :   RefPtr<Timeout> mNormalIter;           // The iterator over the normal timeout list.
     163             :   RefPtr<Timeout> mTrackingIter;         // The iterator over the tracking timeout list.
     164             :   RefPtr<Timeout> mCurrent;              // The current timeout that Next() just found.
     165             :   enum class Kind { Normal, Tracking, None };
     166             :   Kind mKind;                            // The kind of iterator picked the last time.
     167             :   DebugOnly<bool> mUpdateIteratorCalled; // Whether we have called UpdateIterator() before calling Next().
     168             : };
     169             : 
     170             : }
     171             : }
     172             : 
     173             : #endif

Generated by: LCOV version 1.13