Wed, 31 Dec 2014 06:09:35 +0100
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_ */