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 nudsfml.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 	private long m_microseconds;
81 
82 	//Internal constructor
83 	package this(long microseconds) {
84 		m_microseconds = microseconds;
85 	}
86 
87 	/**
88 	 * Return the time value as a number of seconds.
89 	 *
90 	 * Returns: Time in seconds.
91 	 */
92 	float asSeconds() const {
93 		return m_microseconds/1_000_000f;
94 	}
95 
96 	/**
97 	 * Return the time value as a number of milliseconds.
98 	 *
99 	 * Returns: Time in milliseconds.
100 	 */
101 	int asMilliseconds() const {
102 		return cast(int)(m_microseconds / 1_000);
103 	}
104 
105 	/**
106 	 * Return the time value as a number of microseconds.
107 	 *
108 	 * Returns: Time in microseconds.
109 	 */
110 	long asMicroseconds() const {
111 		return m_microseconds;
112 	}
113 
114     /**
115      * Return the time value as a Duration.
116      */
117     Duration asDuration() const {
118         return usecs(m_microseconds);
119     }
120 
121 
122 	/**
123 	 * Predefined "zero" time value.
124 	 */
125 	static immutable(Time) Zero;
126 
127 	bool opEquals(const ref Time rhs) const {
128 		return m_microseconds == rhs.m_microseconds;
129 	}
130 
131 	int opCmp(const ref Time rhs) const {
132 		if(opEquals(rhs)) {
133 			return 0;
134 		} else if(m_microseconds < rhs.m_microseconds) {
135 			return -1;
136 		} else {
137 			return 1;
138 		}
139 
140 
141 	}
142 
143 	/**
144 	* Overload of unary - operator to negate a time value.
145 	*/
146 	Time opUnary(string s)() const
147 	if (s == "-") {
148 		return microseconds(-m_microseconds);
149 	}
150 
151 
152 	/**
153 	 * Overload of binary + and - operators toadd or subtract two time values.
154 	 */
155 	Time opBinary(string op)(Time rhs) const
156 	if((op == "+") || (op == "-")) {
157 		static if (op == "+") {
158 			return microseconds(m_microseconds + rhs.m_microseconds);
159 		} 
160 		static if(op == "-") {
161 			return microseconds(m_microseconds - rhs.m_microseconds);
162 		}
163 	}
164 
165 	/**
166 	 * Overload of += and -= assignment operators.
167 	 */
168 	ref Time opOpAssign(string op)(Time rhs)
169 	if((op == "+") || (op == "-")) {
170 		static if(op == "+") {
171 			m_microseconds += rhs.m_microseconds;
172 			return this;
173 		} 
174 		static if(op == "-"){
175 			m_microseconds -= rhs.m_microseconds;
176 			return this;
177 		}
178 	}
179 
180 
181 	/**
182 	 * Overload of binary * and / operators to scale a time value.
183 	 */
184 	Time opBinary (string op, E)(E num) const
185 	if(isNumeric!(E) && ((op == "*") || (op == "/"))) {
186 		static if (op == "*") {
187 			return microseconds(m_microseconds * num);
188 		}
189 		static if(op == "/") {
190 			return microseconds(m_microseconds / num);
191 		}
192 	}
193 
194 	/**
195 	 * Overload of *= and /= assignment operators.
196 	 */
197 	ref Time opOpAssign(string op,E)(E num)
198 	if(isNumeric!(E) && ((op == "*") || (op == "/"))) {
199 		static if(op == "*") {
200 			m_microseconds *= num;
201 			return this;
202 		}
203 		static if(op == "/") {
204 			m_microseconds /= num;
205 			return this;
206 		}
207 	}
208 
209 }
210 /**
211  * Construct a time value from a number of seconds.
212  *
213  * Params:
214  *   amount = Number of seconds.
215  *
216  * Returns: Time value constructed from the amount of microseconds.
217  */
218 Time seconds(float amount) {
219 	return Time(cast(long)(amount * 1_000_000));
220 }
221 /**
222  *Construct a time value from a number of milliseconds.
223  *
224  * Params:
225  *  	amount = Number of milliseconds.
226  *
227  * Returns: Time value constructed from the amount of microseconds.
228  */
229 Time milliseconds(int amount) {
230 	return Time(amount*1000);
231 }
232 
233 /**
234  * Construct a time value from a number of microseconds.
235  *
236  * Params:
237  *  amount = Number of microseconds.
238  *
239  * Returns: Time value constructed from the amount of microseconds.
240  */
241 Time microseconds(long amount) {
242 	return Time(amount);
243 }
244 
245 /**
246  * Construct a time value from a Duration.
247  *
248  * Params:
249  *  dur = The time duration.
250  *
251  * Returns: Time value constructed from the time duration.
252  */
253 Time duration(Duration dur) {
254     return Time(dur.total!"usecs"());
255 }
256 
257 unittest
258 {
259 	version(DSFML_Unittest_System)
260 	{
261 
262 		import std.stdio;
263 
264 		writeln("Unit test for Time Struct");
265 
266 		auto time = seconds(1);
267 
268 		assert(time.asSeconds() == 1);
269 
270 		assert((time*2).asSeconds() == 2);
271 
272 		assert((time/2).asSeconds() == .5f);
273 
274 		assert((time+seconds(1)).asSeconds() == 2);
275 
276 		assert((time-seconds(1)).asSeconds() == 0);
277 
278 		time += seconds(1);
279 
280 		assert(time.asSeconds() == 2);
281 
282 		time -= seconds(1);
283 
284 		assert(time.asSeconds() == 1);
285 
286 		time/=2;
287 
288 		assert(time.asSeconds() == .5f);
289 
290 		time*=2;
291 
292 		assert(time.asSeconds() == 1);
293 
294 		writeln("Time Struct passes all tests.");
295 		writeln();
296 	}
297 }