content/media/TimeVarying.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial