1 /*
2  * Copyright (c) 2017-2018 sel-project
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all
12  * copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  *
22  */
23 /**
24  * Copyright: 2017-2018 sel-project
25  * License: MIT
26  * Authors: Kripth
27  * Source: $(HTTP github.com/sel-project/selery/source/selery/world/task.d, selery/world/task.d)
28  */
29 module selery.world.task;
30 
31 import selery.about : tick_t;
32 
33 enum areValidTaskArgs(E...) = E.length == 0 || (E.length == 1 && is(E[0] : tick_t));
34 
35 final class TaskManager {
36 	
37 	private size_t tids = 0;
38 	private Task[] tasks;
39 	
40 	public @safe size_t add()(void delegate() task, size_t interval, size_t repeat, tick_t stick) {
41 		this.tasks ~= new Task(this.tids, task, interval, repeat, stick);
42 		return this.tids++;
43 	}
44 	
45 	public @safe bool remove()(void delegate() task) {
46 		foreach(index, t; this.tasks) {
47 			if(t.task == task) {
48 				this.tasks = this.tasks[0..index] ~ this.tasks[index+1..$];
49 				return true;
50 			}
51 		}
52 		return false;
53 	}
54 	
55 	public @safe bool remove(size_t tid) {
56 		foreach(index, task; this.tasks) {
57 			if(task.id == tid) {
58 				this.tasks = this.tasks[0..index] ~ this.tasks[index+1..$];
59 				return true;
60 			}
61 		}
62 		return false;
63 	}
64 	
65 	public void tick(tick_t tick) {
66 		foreach(index, task; this.tasks) {
67 			if(task.expired) this.tasks = this.tasks[0..index] ~ this.tasks[index+1..$];
68 			else task.execute(tick);
69 		}
70 	}
71 	
72 	public pure nothrow @property @safe @nogc size_t length() {
73 		return this.tasks.length;
74 	}
75 	
76 }
77 
78 final class Task {
79 	
80 	public immutable size_t id;
81 	
82 	private void delegate() _task;
83 	private size_t interval;
84 	private size_t repeat;
85 	
86 	private tick_t start;
87 	private tick_t ticks = 0;
88 	
89 	public @safe this(size_t id, void delegate() task, size_t interval, size_t repeat, tick_t start) {
90 		assert(interval != 0, "0 is not a valid interval");
91 		this.id = id;
92 		this._task = task;
93 		this.interval = interval;
94 		this.repeat = repeat;
95 		this.start = start % this.interval;
96 	}
97 	
98 	public pure nothrow @property @safe @nogc bool expired() {
99 		return this.repeat == 0;
100 	}
101 	
102 	public void execute(tick_t stick) {
103 		if(stick % this.interval == this.start) {
104 			this._task();
105 			this.ticks++;
106 			if(this.repeat < uint.max) this.repeat--;
107 		}
108 	}
109 	
110 	public pure nothrow @property @safe @nogc void delegate() task() {
111 		return this._task;
112 	}
113 	
114 }