content/media/TimeVarying.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     4  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #ifndef MOZILLA_TIMEVARYING_H_
     7 #define MOZILLA_TIMEVARYING_H_
     9 #include "nsTArray.h"
    11 namespace mozilla {
    13 /**
    14  * This is just for CTOR/DTOR tracking. We can't put this in
    15  * TimeVarying directly because the different template instances have
    16  * different sizes and that confuses things.
    17  */
    18 class TimeVaryingBase {
    19 protected:
    20   TimeVaryingBase()
    21   {
    22     MOZ_COUNT_CTOR(TimeVaryingBase);
    23   }
    24   ~TimeVaryingBase()
    25   {
    26     MOZ_COUNT_DTOR(TimeVaryingBase);
    27   }
    28 };
    30 /**
    31  * Objects of this class represent values that can change over time ---
    32  * a mathematical function of time.
    33  * Time is the type of time values, T is the value that changes over time.
    34  * There are a finite set of "change times"; at each change time, the function
    35  * instantly changes to a new value. ReservedChanges should be set to the
    36  * expected number of change events that the object is likely to contain.
    37  * This value should be 0 for all consumers unless you know that a higher value
    38  * would be a benefit.
    39  * There is also a "current time" which must always advance (not go backward).
    40  * The function is constant for all times less than the current time.
    41  * When the current time is advanced, the value of the function at the new
    42  * current time replaces the values for all previous times.
    43  *
    44  * The implementation records a mCurrent (the value at the current time)
    45  * and an array of "change times" (greater than the current time) and the
    46  * new value for each change time. This is a simple but dumb implementation.
    47  * We maintain the invariant that each change entry in the array must have
    48  * a different value to the value in the previous change entry (or, for
    49  * the first change entry, mCurrent).
    50  */
    51 template <typename Time, typename T, uint32_t ReservedChanges>
    52 class TimeVarying : public TimeVaryingBase {
    53 public:
    54   TimeVarying(const T& aInitial) : mCurrent(aInitial) {}
    55   /**
    56    * This constructor can only be called if mCurrent has a no-argument
    57    * constructor.
    58    */
    59   TimeVarying() : mCurrent() {}
    61   /**
    62    * Sets the value for all times >= aTime to aValue.
    63    */
    64   void SetAtAndAfter(Time aTime, const T& aValue)
    65   {
    66     for (int32_t i = mChanges.Length() - 1; i >= 0; --i) {
    67       NS_ASSERTION(i == int32_t(mChanges.Length() - 1),
    68                    "Always considering last element of array");
    69       if (aTime > mChanges[i].mTime) {
    70         if (mChanges[i].mValue != aValue) {
    71           mChanges.AppendElement(Entry(aTime, aValue));
    72         }
    73         return;
    74       }
    75       if (aTime == mChanges[i].mTime) {
    76         if ((i > 0 ? mChanges[i - 1].mValue : mCurrent) == aValue) {
    77           mChanges.RemoveElementAt(i);
    78           return;
    79         }
    80         mChanges[i].mValue = aValue;
    81         return;
    82       }
    83       mChanges.RemoveElementAt(i);
    84     }
    85     if (mCurrent == aValue) {
    86       return;
    87     }
    88     mChanges.InsertElementAt(0, Entry(aTime, aValue));
    89   }
    90   /**
    91    * Returns the final value of the function. If aTime is non-null,
    92    * sets aTime to the time at which the function changes to that final value.
    93    * If there are no changes after the current time, returns INT64_MIN in aTime.
    94    */
    95   const T& GetLast(Time* aTime = nullptr) const
    96   {
    97     if (mChanges.IsEmpty()) {
    98       if (aTime) {
    99         *aTime = INT64_MIN;
   100       }
   101       return mCurrent;
   102     }
   103     if (aTime) {
   104       *aTime = mChanges[mChanges.Length() - 1].mTime;
   105     }
   106     return mChanges[mChanges.Length() - 1].mValue;
   107   }
   108   /**
   109    * Returns the value of the function just before time aTime.
   110    */
   111   const T& GetBefore(Time aTime) const
   112   {
   113     if (mChanges.IsEmpty() || aTime <= mChanges[0].mTime) {
   114       return mCurrent;
   115     }
   116     int32_t changesLength = mChanges.Length();
   117     if (mChanges[changesLength - 1].mTime < aTime) {
   118       return mChanges[changesLength - 1].mValue;
   119     }
   120     for (uint32_t i = 1; ; ++i) {
   121       if (aTime <= mChanges[i].mTime) {
   122         NS_ASSERTION(mChanges[i].mValue != mChanges[i - 1].mValue,
   123                      "Only changed values appear in array");
   124         return mChanges[i - 1].mValue;
   125       }
   126     }
   127   }
   128   /**
   129    * Returns the value of the function at time aTime.
   130    * If aEnd is non-null, sets *aEnd to the time at which the function will
   131    * change from the returned value to a new value, or INT64_MAX if that
   132    * never happens.
   133    * If aStart is non-null, sets *aStart to the time at which the function
   134    * changed to the returned value, or INT64_MIN if that happened at or
   135    * before the current time.
   136    *
   137    * Currently uses a linear search, but could use a binary search.
   138    */
   139   const T& GetAt(Time aTime, Time* aEnd = nullptr, Time* aStart = nullptr) const
   140   {
   141     if (mChanges.IsEmpty() || aTime < mChanges[0].mTime) {
   142       if (aStart) {
   143         *aStart = INT64_MIN;
   144       }
   145       if (aEnd) {
   146         *aEnd = mChanges.IsEmpty() ? INT64_MAX : mChanges[0].mTime;
   147       }
   148       return mCurrent;
   149     }
   150     int32_t changesLength = mChanges.Length();
   151     if (mChanges[changesLength - 1].mTime <= aTime) {
   152       if (aEnd) {
   153         *aEnd = INT64_MAX;
   154       }
   155       if (aStart) {
   156         *aStart = mChanges[changesLength - 1].mTime;
   157       }
   158       return mChanges[changesLength - 1].mValue;
   159     }
   161     for (uint32_t i = 1; ; ++i) {
   162       if (aTime < mChanges[i].mTime) {
   163         if (aEnd) {
   164           *aEnd = mChanges[i].mTime;
   165         }
   166         if (aStart) {
   167           *aStart = mChanges[i - 1].mTime;
   168         }
   169         NS_ASSERTION(mChanges[i].mValue != mChanges[i - 1].mValue,
   170                      "Only changed values appear in array");
   171         return mChanges[i - 1].mValue;
   172       }
   173     }
   174   }
   175   /**
   176    * Advance the current time to aTime.
   177    */
   178   void AdvanceCurrentTime(Time aTime)
   179   {
   180     for (uint32_t i = 0; i < mChanges.Length(); ++i) {
   181       if (aTime < mChanges[i].mTime) {
   182         mChanges.RemoveElementsAt(0, i);
   183         return;
   184       }
   185       mCurrent = mChanges[i].mValue;
   186     }
   187     mChanges.Clear();
   188   }
   189   /**
   190    * Make all currently pending changes happen aDelta later than their
   191    * current change times.
   192    */
   193   void InsertTimeAtStart(Time aDelta)
   194   {
   195     for (uint32_t i = 0; i < mChanges.Length(); ++i) {
   196       mChanges[i].mTime += aDelta;
   197     }
   198   }
   200   /**
   201    * Replace the values of this function at aTimeOffset and later with the
   202    * values of aOther taken from zero, so if aOther is V at time T >= 0
   203    * then this function will be V at time T + aTimeOffset. aOther's current
   204    * time must be >= 0.
   205    */
   206   void Append(const TimeVarying& aOther, Time aTimeOffset)
   207   {
   208     NS_ASSERTION(aOther.mChanges.IsEmpty() || aOther.mChanges[0].mTime >= 0,
   209                  "Negative time not allowed here");
   210     NS_ASSERTION(&aOther != this, "Can't self-append");
   211     SetAtAndAfter(aTimeOffset, aOther.mCurrent);
   212     for (uint32_t i = 0; i < aOther.mChanges.Length(); ++i) {
   213       const Entry& e = aOther.mChanges[i];
   214       SetAtAndAfter(aTimeOffset + e.mTime, e.mValue);
   215     }
   216   }
   218   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
   219   {
   220     return mChanges.SizeOfExcludingThis(aMallocSizeOf);
   221   }
   223 private:
   224   struct Entry {
   225     Entry(Time aTime, const T& aValue) : mTime(aTime), mValue(aValue) {}
   227     // The time at which the value changes to mValue
   228     Time mTime;
   229     T mValue;
   230   };
   231   nsAutoTArray<Entry, ReservedChanges> mChanges;
   232   T mCurrent;
   233 };
   235 }
   237 #endif /* MOZILLA_TIMEVARYING_H_ */

mercurial