/* * 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; #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(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 } }