193 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
		
		
			
		
	
	
			193 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
|  | /* | ||
|  |  * Copyright (C)2005-2019 Haxe Foundation | ||
|  |  * | ||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a | ||
|  |  * copy of this software and associated documentation files (the "Software"), | ||
|  |  * to deal in the Software without restriction, including without limitation | ||
|  |  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
|  |  * and/or sell copies of the Software, and to permit persons to whom the | ||
|  |  * Software is furnished to do so, subject to the following conditions: | ||
|  |  * | ||
|  |  * The above copyright notice and this permission notice shall be included in | ||
|  |  * all copies or substantial portions of the Software. | ||
|  |  * | ||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
|  |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
|  |  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
|  |  * DEALINGS IN THE SOFTWARE. | ||
|  |  */ | ||
|  | 
 | ||
|  | package haxe; | ||
|  | 
 | ||
|  | #if (target.threaded && !cppia) | ||
|  | import sys.thread.Thread; | ||
|  | import sys.thread.EventLoop; | ||
|  | #end | ||
|  | 
 | ||
|  | /** | ||
|  | 	The `Timer` class allows you to create asynchronous timers on platforms that | ||
|  | 	support events. | ||
|  | 
 | ||
|  | 	The intended usage is to create an instance of the `Timer` class with a given | ||
|  | 	interval, set its `run()` method to a custom function to be invoked and | ||
|  | 	eventually call `stop()` to stop the `Timer`. | ||
|  | 
 | ||
|  | 	Note that a running `Timer` may or may not prevent the program to exit | ||
|  | 	automatically when `main()` returns. | ||
|  | 
 | ||
|  | 	It is also possible to extend this class and override its `run()` method in | ||
|  | 	the child class. | ||
|  | **/ | ||
|  | class Timer { | ||
|  | 	#if (flash || js) | ||
|  | 	private var id:Null<Int>; | ||
|  | 	#elseif (target.threaded && !cppia) | ||
|  | 	var thread:Thread; | ||
|  | 	var eventHandler:EventHandler; | ||
|  | 	#else | ||
|  | 	private var event:MainLoop.MainEvent; | ||
|  | 	#end | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Creates a new timer that will run every `time_ms` milliseconds. | ||
|  | 
 | ||
|  | 		After creating the Timer instance, it calls `this.run` repeatedly, | ||
|  | 		with delays of `time_ms` milliseconds, until `this.stop` is called. | ||
|  | 
 | ||
|  | 		The first invocation occurs after `time_ms` milliseconds, not | ||
|  | 		immediately. | ||
|  | 
 | ||
|  | 		The accuracy of this may be platform-dependent. | ||
|  | 	**/ | ||
|  | 	public function new(time_ms:Int) { | ||
|  | 		#if flash | ||
|  | 		var me = this; | ||
|  | 		id = untyped __global__["flash.utils.setInterval"](function() { | ||
|  | 			me.run(); | ||
|  | 		}, time_ms); | ||
|  | 		#elseif js | ||
|  | 		var me = this; | ||
|  | 		id = untyped setInterval(function() me.run(), time_ms); | ||
|  | 		#elseif (target.threaded && !cppia) | ||
|  | 		thread = Thread.current(); | ||
|  | 		eventHandler = thread.events.repeat(() -> this.run(), time_ms); | ||
|  | 		#else | ||
|  | 		var dt = time_ms / 1000; | ||
|  | 		event = MainLoop.add(function() { | ||
|  | 			@:privateAccess event.nextRun += dt; | ||
|  | 			run(); | ||
|  | 		}); | ||
|  | 		event.delay(dt); | ||
|  | 		#end | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Stops `this` Timer. | ||
|  | 
 | ||
|  | 		After calling this method, no additional invocations of `this.run` | ||
|  | 		will occur. | ||
|  | 
 | ||
|  | 		It is not possible to restart `this` Timer once stopped. | ||
|  | 	**/ | ||
|  | 	public function stop() { | ||
|  | 		#if (flash || js) | ||
|  | 		if (id == null) | ||
|  | 			return; | ||
|  | 		#if flash | ||
|  | 		untyped __global__["flash.utils.clearInterval"](id); | ||
|  | 		#elseif js | ||
|  | 		untyped clearInterval(id); | ||
|  | 		#end | ||
|  | 		id = null; | ||
|  | 		#elseif (target.threaded && !cppia) | ||
|  | 		thread.events.cancel(eventHandler); | ||
|  | 		#else | ||
|  | 		if (event != null) { | ||
|  | 			event.stop(); | ||
|  | 			event = null; | ||
|  | 		} | ||
|  | 		#end | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		This method is invoked repeatedly on `this` Timer. | ||
|  | 
 | ||
|  | 		It can be overridden in a subclass, or rebound directly to a custom | ||
|  | 		function: | ||
|  | 
 | ||
|  | 		```haxe | ||
|  | 		var timer = new haxe.Timer(1000); // 1000ms delay | ||
|  | 		timer.run = function() { ... } | ||
|  | 		``` | ||
|  | 
 | ||
|  | 		Once bound, it can still be rebound to different functions until `this` | ||
|  | 		Timer is stopped through a call to `this.stop`. | ||
|  | 	**/ | ||
|  | 	public dynamic function run() {} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Invokes `f` after `time_ms` milliseconds. | ||
|  | 
 | ||
|  | 		This is a convenience function for creating a new Timer instance with | ||
|  | 		`time_ms` as argument, binding its `run()` method to `f` and then stopping | ||
|  | 		`this` Timer upon the first invocation. | ||
|  | 
 | ||
|  | 		If `f` is `null`, the result is unspecified. | ||
|  | 	**/ | ||
|  | 	public static function delay(f:Void->Void, time_ms:Int) { | ||
|  | 		var t = new haxe.Timer(time_ms); | ||
|  | 		t.run = function() { | ||
|  | 			t.stop(); | ||
|  | 			f(); | ||
|  | 		}; | ||
|  | 		return t; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Measures the time it takes to execute `f`, in seconds with fractions. | ||
|  | 
 | ||
|  | 		This is a convenience function for calculating the difference between | ||
|  | 		`Timer.stamp()` before and after the invocation of `f`. | ||
|  | 
 | ||
|  | 		The difference is passed as argument to `Log.trace()`, with `"s"` appended | ||
|  | 		to denote the unit. The optional `pos` argument is passed through. | ||
|  | 
 | ||
|  | 		If `f` is `null`, the result is unspecified. | ||
|  | 	**/ | ||
|  | 	public static function measure<T>(f:Void->T, ?pos:PosInfos):T { | ||
|  | 		var t0 = stamp(); | ||
|  | 		var r = f(); | ||
|  | 		Log.trace((stamp() - t0) + "s", pos); | ||
|  | 		return r; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Returns a timestamp, in seconds with fractions. | ||
|  | 
 | ||
|  | 		The value itself might differ depending on platforms, only differences | ||
|  | 		between two values make sense. | ||
|  | 	**/ | ||
|  | 	public static inline function stamp():Float { | ||
|  | 		#if flash | ||
|  | 		return flash.Lib.getTimer() / 1000; | ||
|  | 		#elseif js | ||
|  | 		#if nodejs | ||
|  | 		var hrtime = js.Syntax.code('process.hrtime()'); // [seconds, remaining nanoseconds] | ||
|  | 		return hrtime[0] + hrtime[1] / 1e9; | ||
|  | 		#else | ||
|  | 		return @:privateAccess HxOverrides.now() / 1000; | ||
|  | 		#end | ||
|  | 		#elseif cpp | ||
|  | 		return untyped __global__.__time_stamp(); | ||
|  | 		#elseif python | ||
|  | 		return Sys.cpuTime(); | ||
|  | 		#elseif sys | ||
|  | 		return Sys.time(); | ||
|  | 		#else | ||
|  | 		return 0; | ||
|  | 		#end | ||
|  | 	} | ||
|  | } |