1 /** 2 Copyright: Copyright (c) 2013-2014 Andrey Penechko. 3 License: a$(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 7 module emulator.dcpu.updatequeue; 8 9 import std.algorithm : swap, filter, sort; 10 import std.stdio; 11 12 import emulator.dcpu.devices.idevice; 13 14 struct UpdateQuery(Cpu) 15 { 16 IDevice!Cpu device; 17 ulong delay; 18 } 19 20 struct UpdateQueue(Cpu) 21 { 22 ulong ticksAccumulated; 23 bool empty = true; 24 UpdateQuery!Cpu*[] queries; 25 26 void onTick(ulong ticksElapsed) 27 { 28 ticksAccumulated += ticksElapsed; 29 30 if (!empty && ticksAccumulated > queries[0].delay) 31 { 32 queries_loop: 33 foreach(ref query; queries) 34 { 35 ulong ticks = ticksAccumulated; 36 while (ticks >= query.delay) 37 { 38 ticks -= query.delay; 39 query.device.handleUpdateQuery(query.delay); 40 //writefln("delay %s", query.delay); 41 if (query.delay == 0) // remove query 42 { 43 destroy(query); 44 continue queries_loop; 45 } 46 } 47 48 query.delay -= ticks; 49 } 50 51 //writefln("queries %s", queries); 52 53 UpdateQuery!Cpu*[] tempQueries = queries; 54 queries.length = 0; 55 56 foreach(ref query; tempQueries.filter!((a) => a !is null)) 57 { 58 queries.assumeSafeAppend() ~= query; 59 } 60 61 //writefln("queries %s", queries); 62 63 ticksAccumulated = 0; 64 65 if (queries.length == 0) 66 { 67 empty = true; 68 return; 69 } 70 71 //writefln("queries %s", queries); 72 73 sort!("a.delay < b.delay")(queries); 74 75 //writefln("queries %s", queries); 76 } 77 78 //writefln("on tick %s", queries); 79 } 80 81 /// Adds update query 82 void addQuery(IDevice!Cpu device, ulong delay) 83 { 84 //writefln("begin add %s, %s", device, queries); 85 ulong realDelay = delay + ticksAccumulated; 86 87 queries ~= new UpdateQuery!Cpu(device, realDelay); 88 89 foreach(i, query; queries) 90 { 91 if ((*query).delay > realDelay) // found place 92 { 93 foreach_reverse(j; i+1..queries.length) 94 { 95 swap(queries[j], queries[j-1]); 96 } 97 98 break; 99 } 100 } 101 102 empty = false; 103 104 //writefln("end add %s", queries); 105 } 106 107 /// Removes all occurences of device in queries in place. 108 void removeQueries(IDevice!Cpu device) 109 { 110 //writefln("begin remove %s, %s", device, queries); 111 UpdateQuery!Cpu*[] tempQueries = queries; 112 queries.length = 0; 113 114 foreach(ref query; tempQueries.filter!((a) => (*a).device != device)) 115 { 116 queries.assumeSafeAppend() ~= query; 117 } 118 119 if (queries.length == 0) empty = true; 120 121 //writefln("end remove %s", queries); 122 } 123 }