wasSharp – Blame information for rev 7

Subversion Repositories:
Rev:
Rev Author Line No. Line
2 zed 1 ///////////////////////////////////////////////////////////////////////////
2 // Copyright (C) Wizardry and Steamworks 2013 - License: GNU GPLv3 //
3 // Please see: http://www.gnu.org/licenses/gpl.html for legal details, //
4 // rights of fair usage, the disclaimer and warranty conditions. //
5 ///////////////////////////////////////////////////////////////////////////
6  
7 using System;
8 using System.Collections.Generic;
9 using System.Diagnostics;
10 using System.Linq;
11 using System.Threading;
12 using System.Threading.Tasks;
13 using System.Xml.Serialization;
14  
15 namespace wasSharp
16 {
7 office 17 public static class Time
2 zed 18 {
19 public delegate void TimerCallback(object state);
20  
6 eva 21 /// <summary>
22 /// Convert an Unix timestamp to a DateTime structure.
23 /// </summary>
24 /// <param name="unixTimestamp">the Unix timestamp to convert</param>
25 /// <returns>the DateTime structure</returns>
26 /// <remarks>the function assumes UTC time</remarks>
27 public static DateTime UnixTimestampToDateTime(uint unixTimestamp)
28 {
29 return new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(unixTimestamp).ToUniversalTime();
30 }
31  
32 /// <summary>
33 /// Convert a DateTime structure to a Unix timestamp.
34 /// </summary>
35 /// <param name="dateTime">the DateTime structure to convert</param>
36 /// <returns>the Unix timestamp</returns>
37 /// <remarks>the function assumes UTC time</remarks>
38 public static uint DateTimeToUnixTimestamp(DateTime dateTime)
39 {
40 return (uint) (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
41 }
42  
2 zed 43 public sealed class Timer : IDisposable
44 {
45 private static readonly Task CompletedTask = Task.FromResult(false);
46 private readonly TimerCallback Callback;
47 private readonly object State;
48 private Task Delay;
49 private bool Disposed;
50 private int Period;
51 private CancellationTokenSource TokenSource;
52  
53 public Timer(TimerCallback callback, object state, int dueTime, int period)
54 {
55 Callback = callback;
56 State = state;
57 Period = period;
58 Reset(dueTime);
59 }
60  
61 public Timer(TimerCallback callback, object state, TimeSpan dueTime, TimeSpan period)
62 : this(callback, state, (int) dueTime.TotalMilliseconds, (int) period.TotalMilliseconds)
63 {
64 }
65  
7 office 66 public Timer(TimerCallback callback) : this(callback, null, TimeSpan.Zero, TimeSpan.Zero)
67 {
68 }
69  
2 zed 70 public void Dispose()
71 {
72 Dispose(true);
73 GC.SuppressFinalize(this);
74 }
75  
76 ~Timer()
77 {
78 Dispose(false);
79 }
80  
81 private void Dispose(bool cleanUpManagedObjects)
82 {
83 if (cleanUpManagedObjects)
84 Cancel();
85 Disposed = true;
86 }
87  
88 public void Change(int dueTime, int period)
89 {
90 Period = period;
91 Reset(dueTime);
92 }
93  
7 office 94 public void Change(uint dueTime, int period)
95 {
96 Period = period;
97 Change((int) dueTime, period);
98 }
99  
2 zed 100 public void Change(TimeSpan dueTime, TimeSpan period)
101 {
102 Change((int) dueTime.TotalMilliseconds, (int) period.TotalMilliseconds);
103 }
104  
105 private void Reset(int due)
106 {
107 Cancel();
7 office 108 if (due <= 0)
109 return;
110 TokenSource = new CancellationTokenSource();
111 Action tick = null;
112 tick = () =>
2 zed 113 {
7 office 114 Task.Run(() => Callback(State));
115 if (Disposed)
116 return;
117 Delay = Period > 0 ? Task.Delay(Period, TokenSource.Token) : CompletedTask;
118 if (Delay.IsCompleted)
119 return;
2 zed 120 Delay.ContinueWith(t => tick(), TokenSource.Token);
7 office 121 };
122 Delay = due > 0 ? Task.Delay(due, TokenSource.Token) : CompletedTask;
123 if (Delay.IsCompleted)
124 return;
125 Delay.ContinueWith(t => tick(), TokenSource.Token);
2 zed 126 }
127  
7 office 128 public void Stop()
129 {
130 Change(0, 0);
131 }
132  
2 zed 133 private void Cancel()
134 {
7 office 135 if (TokenSource == null)
136 return;
137 TokenSource.Cancel();
138 TokenSource.Dispose();
139 TokenSource = null;
2 zed 140 }
141 }
142  
143 ///////////////////////////////////////////////////////////////////////////
144 // Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 //
145 ///////////////////////////////////////////////////////////////////////////
146 /// <summary>
147 /// Given a number of allowed events per seconds, this class allows you
148 /// to determine via the IsSafe property whether it is safe to trigger
149 /// another lined-up event. This is mostly used to check that throttles
150 /// are being respected.
151 /// </summary>
7 office 152 public sealed class TimedThrottle : IDisposable
2 zed 153 {
154 private readonly uint EventsAllowed;
155 private readonly object LockObject = new object();
156 private Timer timer;
7 office 157 public uint TriggeredEvents;
2 zed 158  
5 eva 159 public TimedThrottle(uint events, uint seconds)
2 zed 160 {
161 EventsAllowed = events;
162 if (timer == null)
163 {
164 timer = new Timer(o =>
165 {
166 lock (LockObject)
167 {
168 TriggeredEvents = 0;
169 }
170 }, null, (int) seconds, (int) seconds);
171 }
172 }
173  
174 public bool IsSafe
175 {
176 get
177 {
178 lock (LockObject)
179 {
180 return ++TriggeredEvents <= EventsAllowed;
181 }
182 }
183 }
184  
185 public void Dispose()
186 {
187 Dispose(true);
188 GC.SuppressFinalize(this);
189 }
190  
7 office 191 ~TimedThrottle()
2 zed 192 {
7 office 193 Dispose(false);
194 }
195  
196 private void Dispose(bool dispose)
197 {
2 zed 198 if (timer != null)
199 {
200 timer.Dispose();
201 timer = null;
202 }
203 }
204 }
205  
206 ///////////////////////////////////////////////////////////////////////////
207 // Copyright (C) Wizardry and Steamworks 2013 - License: GNU GPLv3 //
208 ///////////////////////////////////////////////////////////////////////////
209 /// <summary>
210 /// An alarm class similar to the UNIX alarm with the added benefit
211 /// of a decaying timer that tracks the time between rescheduling.
212 /// </summary>
213 /// <remarks>
214 /// (C) Wizardry and Steamworks 2013 - License: GNU GPLv3
215 /// </remarks>
7 office 216 public sealed class DecayingAlarm : IDisposable
2 zed 217 {
218 [Flags]
219 public enum DECAY_TYPE
220 {
7 office 221 [Reflection.NameAttribute("none")] [XmlEnum(Name = "none")] NONE = 0,
222 [Reflection.NameAttribute("arithmetic")] [XmlEnum(Name = "arithmetic")] ARITHMETIC = 1,
223 [Reflection.NameAttribute("geometric")] [XmlEnum(Name = "geometric")] GEOMETRIC = 2,
224 [Reflection.NameAttribute("harmonic")] [XmlEnum(Name = "harmonic")] HARMONIC = 4,
225 [Reflection.NameAttribute("weighted")] [XmlEnum(Name = "weighted")] WEIGHTED = 5
2 zed 226 }
227  
228 private readonly DECAY_TYPE decay = DECAY_TYPE.NONE;
229 private readonly Stopwatch elapsed = new Stopwatch();
230 private readonly object LockObject = new object();
231 private readonly HashSet<double> times = new HashSet<double>();
232 private Timer alarm;
233  
234 /// <summary>
235 /// The default constructor using no decay.
236 /// </summary>
5 eva 237 public DecayingAlarm()
2 zed 238 {
239 Signal = new ManualResetEvent(false);
240 }
241  
242 /// <summary>
5 eva 243 /// The constructor for the DecayingAlarm class taking as parameter a decay type.
2 zed 244 /// </summary>
245 /// <param name="decay">the type of decay: arithmetic, geometric, harmonic, heronian or quadratic</param>
5 eva 246 public DecayingAlarm(DECAY_TYPE decay)
2 zed 247 {
248 Signal = new ManualResetEvent(false);
249 this.decay = decay;
250 }
251  
252 public ManualResetEvent Signal { get; set; }
253  
254 public void Dispose()
255 {
256 Dispose(true);
257 GC.SuppressFinalize(this);
258 }
259  
7 office 260 ~DecayingAlarm()
261 {
262 Dispose(false);
263 }
264  
2 zed 265 public void Alarm(double deadline)
266 {
267 lock (LockObject)
268 {
269 switch (alarm == null)
270 {
271 case true:
272 elapsed.Start();
273 alarm = new Timer(o =>
274 {
275 lock (LockObject)
276 {
277 Signal.Set();
278 elapsed.Stop();
279 times.Clear();
280 alarm.Dispose();
281 alarm = null;
282 }
283 }, null, (int) deadline, 0);
284 return;
285 case false:
286 elapsed.Stop();
287 times.Add(elapsed.ElapsedMilliseconds);
288 switch (decay)
289 {
290 case DECAY_TYPE.ARITHMETIC:
291 alarm?.Change(
292 (int) ((deadline + times.Aggregate((a, b) => b + a))/(1f + times.Count)), 0);
293 break;
294 case DECAY_TYPE.GEOMETRIC:
7 office 295 alarm?.Change((int) Math.Pow(deadline*times.Aggregate((a, b) => b*a),
296 1f/(1f + times.Count)), 0);
2 zed 297 break;
298 case DECAY_TYPE.HARMONIC:
299 alarm?.Change((int) ((1f + times.Count)/
300 (1f/deadline + times.Aggregate((a, b) => 1f/b + 1f/a))), 0);
301 break;
302 case DECAY_TYPE.WEIGHTED:
7 office 303 var d = new HashSet<double>(times) {deadline};
304 var total = d.Aggregate((a, b) => b + a);
2 zed 305 alarm?.Change(
7 office 306 (int) d.Aggregate((a, b) => Math.Pow(a, 2)/total + Math.Pow(b, 2)/total), 0);
2 zed 307 break;
308 default:
309 alarm?.Change((int) deadline, 0);
310 break;
311 }
312 elapsed.Reset();
313 elapsed.Start();
314 break;
315 }
316 }
317 }
318  
7 office 319 private void Dispose(bool dispose)
2 zed 320 {
321 if (alarm != null)
322 {
323 alarm.Dispose();
324 alarm = null;
325 }
326 }
7 office 327  
328 public DecayingAlarm Clone()
329 {
330 return new DecayingAlarm(decay);
331 }
2 zed 332 }
333 }
334 }