1 /*
2  * DSFML - The Simple and Fast Multimedia Library for D
3  *
4  * Copyright (c) 2013 - 2018 Jeremy DeHaan (dehaan.jeremiah@gmail.com)
5  *
6  * This software is provided 'as-is', without any express or implied warranty.
7  * In no event will the authors be held liable for any damages arising from the
8  * use of this software.
9  *
10  * Permission is granted to anyone to use this software for any purpose,
11  * including commercial applications, and to alter it and redistribute it
12  * freely, subject to the following restrictions:
13  *
14  * 1. The origin of this software must not be misrepresented; you must not claim
15  * that you wrote the original software. If you use this software in a product,
16  * an acknowledgment in the product documentation would be appreciated but is
17  * not required.
18  *
19  * 2. Altered source versions must be plainly marked as such, and must not be
20  * misrepresented as being the original software.
21  *
22  * 3. This notice may not be removed or altered from any source distribution
23  *
24  *
25  * DSFML is based on SFML (Copyright Laurent Gomila)
26  */
27 
28  /**
29  * $(U Time) encapsulates a time value in a flexible way. It allows to define a
30  * time value either as a number of seconds, milliseconds or microseconds. It
31  * also works the other way round: you can read a time value as either a number
32  * of seconds, milliseconds or microseconds.
33  *
34  * By using such a flexible interface, the API doesn't impose any fixed type or
35  * resolution for time values, and let the user choose its own favorite
36  * representation.
37  *
38  * Time values support the usual mathematical operations:
39  * you can add or subtract two times, multiply or divide  a time by a number,
40  * compare two times, etc.
41  *
42  * Since they represent a time span and not an absolute time value, times can
43  * also be negative.
44  *
45  * Example:
46  * ---
47  * Time t1 = seconds(0.1f);
48  * Int milli = t1.asMilliseconds(); // 100
49  *
50  * Time t2 = sf::milliseconds(30);
51  * long micro = t2.asMicroseconds(); // 30000
52  *
53  * Time t3 = sf::microseconds(-800000);
54  * float sec = t3.asSeconds(); // -0.8
55  * ---
56  *
57  * ---
58  * void update(Time elapsed)
59  * {
60  *    position += speed * elapsed.asSeconds();
61  * }
62  *
63  * update(milliseconds(100));
64  * ---
65  *
66  * See_Also:
67  * $(CLOCK_LINK)
68  */
69  module dsfml.system.time;
70 
71 public import core.time: Duration;
72 import core.time: usecs;
73 
74  import std.traits: isNumeric;
75 
76 /**
77  * Represents a time value.
78  */
79  struct Time
80 {
81 	private long m_microseconds;
82 
83 	//Internal constructor
84 	package this(long microseconds)
85 	{
86 		m_microseconds = microseconds;
87 	}
88 
89 	/**
90 	 * Return the time value as a number of seconds.
91 	 *
92 	 * Returns: Time in seconds.
93 	 */
94 	float asSeconds() const
95 	{
96 		return m_microseconds/1_000_000f;
97 	}
98 
99 	/**
100 	 * Return the time value as a number of milliseconds.
101 	 *
102 	 * Returns: Time in milliseconds.
103 	 */
104 	int asMilliseconds() const
105 	{
106 		return cast(int)(m_microseconds / 1_000);
107 	}
108 
109 	/**
110 	 * Return the time value as a number of microseconds.
111 	 *
112 	 * Returns: Time in microseconds.
113 	 */
114 	long asMicroseconds() const
115 	{
116 		return m_microseconds;
117 	}
118 
119     /**
120      * Return the time value as a Duration.
121      */
122     Duration asDuration() const
123     {
124         return usecs(m_microseconds);
125     }
126 
127 
128 	/**
129 	 * Predefined "zero" time value.
130 	 */
131 	static immutable(Time) Zero;
132 
133 	bool opEquals(const ref Time rhs) const
134 	{
135 		return m_microseconds == rhs.m_microseconds;
136 	}
137 
138 	int opCmp(const ref Time rhs) const
139 	{
140 		if(opEquals(rhs))
141 		{
142 			return 0;
143 		}
144 		else if(m_microseconds < rhs.m_microseconds)
145 		{
146 			return -1;
147 		}
148 		else
149 		{
150 			return 1;
151 		}
152 
153 
154 	}
155 
156 	/**
157 	* Overload of unary - operator to negate a time value.
158 	*/
159 	Time opUnary(string s)() const
160 	if (s == "-")
161 	{
162 		return microseconds(-m_microseconds);
163 	}
164 
165 
166 	/**
167 	 * Overload of binary + and - operators toadd or subtract two time values.
168 	 */
169 	Time opBinary(string op)(Time rhs) const
170 	if((op == "+") || (op == "-"))
171 	{
172 		static if (op == "+")
173 		{
174 			return microseconds(m_microseconds + rhs.m_microseconds);
175 		}
176 		static if(op == "-")
177 		{
178 			return microseconds(m_microseconds - rhs.m_microseconds);
179 		}
180 	}
181 
182 	/**
183 	 * Overload of += and -= assignment operators.
184 	 */
185 	ref Time opOpAssign(string op)(Time rhs)
186 	if((op == "+") || (op == "-"))
187 	{
188 		static if(op == "+")
189 		{
190 			m_microseconds += rhs.m_microseconds;
191 			return this;
192 		}
193 		static if(op == "-")
194 		{
195 			m_microseconds -= rhs.m_microseconds;
196 			return this;
197 		}
198 	}
199 
200 
201 	/**
202 	 * Overload of binary * and / operators to scale a time value.
203 	 */
204 	Time opBinary (string op, E)(E num) const
205 	if(isNumeric!(E) && ((op == "*") || (op == "/")))
206 	{
207 		static if (op == "*")
208 		{
209 			return microseconds(m_microseconds * num);
210 		}
211 		static if(op == "/")
212 		{
213 			return microseconds(m_microseconds / num);
214 		}
215 	}
216 
217 	/**
218 	 * Overload of *= and /= assignment operators.
219 	 */
220 	ref Time opOpAssign(string op,E)(E num)
221 	if(isNumeric!(E) && ((op == "*") || (op == "/")))
222 	{
223 		static if(op == "*")
224 		{
225 			m_microseconds *= num;
226 			return this;
227 		}
228 		static if(op == "/")
229 		{
230 			m_microseconds /= num;
231 			return this;
232 		}
233 	}
234 
235 }
236 /**
237  * Construct a time value from a number of seconds.
238  *
239  * Params:
240  *   amount = Number of seconds.
241  *
242  * Returns: Time value constructed from the amount of microseconds.
243  */
244 Time seconds(float amount)
245 {
246 	return Time(cast(long)(amount * 1000000));
247 }
248 /**
249  *Construct a time value from a number of milliseconds.
250  *
251  * Params:
252  *  	amount = Number of milliseconds.
253  *
254  * Returns: Time value constructed from the amount of microseconds.
255  */
256 Time milliseconds(int amount)
257 {
258 	return Time(amount*1000);
259 }
260 
261 /**
262  * Construct a time value from a number of microseconds.
263  *
264  * Params:
265  *  amount = Number of microseconds.
266  *
267  * Returns: Time value constructed from the amount of microseconds.
268  */
269 Time microseconds(long amount)
270 {
271 	return Time(amount);
272 }
273 
274 /**
275  * Construct a time value from a Duration.
276  *
277  * Params:
278  *  dur = The time duration.
279  *
280  * Returns: Time value constructed from the time duration.
281  */
282 Time duration(Duration dur)
283 {
284     return Time(dur.total!"usecs"());
285 }
286 
287 unittest
288 {
289 	version(DSFML_Unittest_System)
290 	{
291 
292 		import std.stdio;
293 
294 		writeln("Unit test for Time Struct");
295 
296 		auto time = seconds(1);
297 
298 		assert(time.asSeconds() == 1);
299 
300 		assert((time*2).asSeconds() == 2);
301 
302 		assert((time/2).asSeconds() == .5f);
303 
304 		assert((time+seconds(1)).asSeconds() == 2);
305 
306 		assert((time-seconds(1)).asSeconds() == 0);
307 
308 		time += seconds(1);
309 
310 		assert(time.asSeconds() == 2);
311 
312 		time -= seconds(1);
313 
314 		assert(time.asSeconds() == 1);
315 
316 		time/=2;
317 
318 		assert(time.asSeconds() == .5f);
319 
320 		time*=2;
321 
322 		assert(time.asSeconds() == 1);
323 
324 		writeln("Time Struct passes all tests.");
325 		writeln();
326 	}
327 }