xeij/TickerQueue.java
//========================================================================================
// TickerQueue.java
// en:Sort of a simple task scheduler
// ja:簡易タスクスケジューラのようなもの
// Copyright (C) 2003-2026 Makoto Kamada
//
// This file is part of the XEiJ (X68000 Emulator in Java).
// You can use, modify and redistribute the XEiJ if the conditions are met.
// Read the XEiJ License for more details.
// https://stdkmd.net/xeij/
//========================================================================================
package xeij;
public class TickerQueue {
//class Ticker
// ティッカー
public static abstract class Ticker {
Ticker () {
time = Long.MAX_VALUE; //キューにない
}
long time; //実行時刻。キューにないときLong.MAX_VALUE
// tickが呼び出された時点でthisはキューから削除されている
// tickの中でtkqAddを呼び出してthisまたは他のティッカーをキューに追加できる
// tickの中でtkqRemoveを呼び出して他のティッカーをキューから削除できる
// tickの中でtkqRunを呼び出してはならない
abstract void tick ();
} //class Ticker
//キュー
// キューに近いソート済み集合
static final int TKQ_S = 256; //容量。2の累乗
static final Ticker[] tkqArray = new Ticker[TKQ_S]; //配列。未使用領域は不定
// w-r 使用量
// r==w 空
// s-(w-r) 空き容量
// (w-r)==s 満杯
// w&(s-1) 末尾+1のインデックス
// r&(s-1) 先頭のインデックス
static int tkqR; //先頭。読み出した回数の下位32bit
static int tkqW; //末尾+1。書き込んだ回数の下位32bit
static final boolean TKQ_NULL = true; //true=未使用領域をnullにする
//tkqInit ()
// 初期化
public static void tkqInit () {
//tkqArray = new Ticker[TKQ_S];
tkqR = 0;
tkqW = 0;
if (false) {
tkqTest ();
}
} //tkqInit
//tkqRun (time)
// 実行
// 指定された時刻までの実行時刻を持つティッカーをキューから削除して実行する
public static void tkqRun (long time) {
Ticker ticker;
while (tkqR != tkqW && //キューが空でなくて
(ticker = tkqArray[tkqR & (TKQ_S - 1)]).time <= time) { //先頭のティッカーが実行時刻になっている
ticker.time = Long.MAX_VALUE; //キューから削除する
if (TKQ_NULL) {
tkqArray[tkqR & (TKQ_S - 1)] = null; //未使用領域をnullにする
}
tkqR++; //先頭を進める
ticker.tick (); //実行する。ここでtkqRやtkqWが動く場合があることに注意
}
} //tkqRun
//tkqAdd (ticker, time)
// 追加
// 指定されたティッカーに指定された時刻を持たせてキューに追加する
public static void tkqAdd (Ticker ticker, long time) {
tkqRemove (ticker); //キューにあれば削除する
if ((tkqW - tkqR) == TKQ_S) { //キューが満杯
throw new Error ("tkqAdd: overflow");
}
ticker.time = time; //キューに追加する
int w = tkqW; //後ろから
Ticker t;
while (tkqR < w &&
time < (t = tkqArray[(w - 1) & (TKQ_S - 1)]).time) { //探す
tkqArray[w & (TKQ_S - 1)] = t; //後ろを後ろにずらす
w--;
}
tkqArray[w & (TKQ_S - 1)] = ticker;
tkqW++; //末尾を進める
} //tkqAdd
//tkqRemove (ticker)
// 削除
// 指定されたティッカーがキューにあればキューから削除する。なければ何もしない
public static void tkqRemove (Ticker ticker) {
if (ticker.time == Long.MAX_VALUE) { //キューにない
return;
}
ticker.time = Long.MAX_VALUE; //削除する
int r = tkqR; //先頭から
while (tkqArray[r & (TKQ_S - 1)] != ticker) { //探す。必ずある
r++;
}
while (tkqR < r) {
tkqArray[r & (TKQ_S - 1)] = tkqArray[(r - 1) & (TKQ_S - 1)]; //手前を後ろにずらす
r--;
}
if (TKQ_NULL) {
tkqArray[r & (TKQ_S - 1)] = null; //未使用領域をnullにする
}
tkqR++; //先頭を進める
} //tkqRemove
//tkqTest ()
// テスト
static void tkqTest () {
//準備
int n = 200;
Ticker[] a = new Ticker[n];
for (int i = 0; i < n; i++) {
a[i] = new Ticker () {
@Override void tick () {
}
};
}
//昇順書き込み
for (int i = 0; i < n; i++) {
tkqAdd (a[i], i);
}
if (tkqW - tkqR != n) {
System.out.println ("tkqTest: error 1");
return;
}
for (int i = 0; i < n; i++) {
if (tkqArray[(tkqR + i) & (TKQ_S - 1)] != a[i]) {
System.out.println ("tkqTest: error 2");
return;
}
}
//昇順削除
for (int i = 0; i < n; i++) {
tkqRemove (a[i]);
}
if (tkqW - tkqR != 0) {
System.out.println ("tkqTest: error 3");
return;
}
//昇順書き込み
for (int i = 0; i < n; i++) {
tkqAdd (a[i], i);
}
if (tkqW - tkqR != n) {
System.out.println ("tkqTest: error 4");
return;
}
for (int i = 0; i < n; i++) {
if (tkqArray[(tkqR + i) & (TKQ_S - 1)] != a[i]) {
System.out.println ("tkqTest: error 5");
return;
}
}
//降順削除
for (int i = 0; i < n; i++) {
tkqRemove (a[n - 1 - i]);
}
if (tkqW - tkqR != 0) {
System.out.println ("tkqTest: error 6");
return;
}
//降順書き込み
for (int i = 0; i < n; i++) {
tkqAdd (a[n - 1 - i], n - 1 - i);
}
if (tkqW - tkqR != n) {
System.out.println ("tkqTest: error 7");
return;
}
for (int i = 0; i < n; i++) {
if (tkqArray[(tkqR + i) & (TKQ_S - 1)] != a[i]) {
System.out.println ("tkqTest: error 8");
return;
}
}
//昇順削除
for (int i = 0; i < n; i++) {
tkqRemove (a[i]);
}
if (tkqW - tkqR != 0) {
System.out.println ("tkqTest: error 9");
return;
}
//降順書き込み
for (int i = 0; i < n; i++) {
tkqAdd (a[n - 1 - i], n - 1 - i);
}
if (tkqW - tkqR != n) {
System.out.println ("tkqTest: error 10");
return;
}
for (int i = 0; i < n; i++) {
if (tkqArray[(tkqR + i) & (TKQ_S - 1)] != a[i]) {
System.out.println ("tkqTest: error 11");
return;
}
}
//降順削除
for (int i = 0; i < n; i++) {
tkqRemove (a[n - 1 - i]);
}
if (tkqW - tkqR != 0) {
System.out.println ("tkqTest: error 12");
return;
}
} //tkqTest
} //class TickerQueue