package a6; public class Timer { @FunctionalInterface public interface ITimerFunc { public void OnTimer(XParams param); } @FunctionalInterface public interface ITimerAfterFunc { public void OnTimerAfter(XParams param); } @FunctionalInterface public interface IGetTickCountFunc { public long GetTickCount(Object context); } private enum TimerType { DEADLINE, REPEAT, FIXED } public class TimerList { private ListHead entry = new ListHead(); private ListHead attachEntry; private TimerType timerType = TimerType.DEADLINE; private int milli_seconds = 0; private long expires = 0; private int fixedTimerExecuteTimes = 0; private ITimerFunc timerFunc; private ITimerAfterFunc timerAfterFunc; private XParams param; private void initTimerList(Timer timer, TimerType timer_type, int milli_seconds, XParams param, ITimerFunc timerFunc, ITimerAfterFunc afterFunc) { this.timerType = timer_type; this.expires = timer.getTickCount.GetTickCount(timer.content) + milli_seconds; this.milli_seconds = milli_seconds; this.fixedTimerExecuteTimes = 0; this.timerFunc = timerFunc; this.timerAfterFunc = afterFunc; this.param = param; } } private static final boolean CONFIG_BASE_SMALL = false; private static final int TVN_BITS = CONFIG_BASE_SMALL ? 4 : 6; private static final int TVR_BITS = CONFIG_BASE_SMALL ? 6 : 8; private static final int TVN_SIZE = 1 << TVN_BITS; private static final int TVR_SIZE = 1 << TVR_BITS; private static final int TVN_MASK = TVN_SIZE - 1; private static final int TVR_MASK = TVR_SIZE - 1; private int freeTimerNum = 0; private ListHead freeTimer = new ListHead(); private TimerList runningTimer; private long timerTick = 0; private IGetTickCountFunc getTickCount; private Object content; private int gcTime = 0; private int cacheTimerNum = 0; private ListHead[] tv1 = SysUtils.newArray(ListHead.class, TVR_SIZE); private ListHead[] tv2 = SysUtils.newArray(ListHead.class, TVN_SIZE); private ListHead[] tv3 = SysUtils.newArray(ListHead.class, TVN_SIZE); private ListHead[] tv4 = SysUtils.newArray(ListHead.class, TVN_SIZE); private ListHead[] tv5 = SysUtils.newArray(ListHead.class, TVN_SIZE); private ListHead workList = new ListHead(); private ListHead cascadeList = new ListHead(); public void init(IGetTickCountFunc func, Object content, int gc_time, int cache_timer_num) { this.getTickCount = func; this.content = content; this.gcTime = gc_time; this.cacheTimerNum = cache_timer_num; } public void unInit() { clear(); } public void update() { while (getTickCount.GetTickCount(content) >= timerTick) { int index = (int)(timerTick & TVR_MASK); if (index == 0 && cascade(tv2, getTimerIndex(index)) == 0 && cascade(tv3, getTimerIndex(index)) == 0 && cascade(tv4, getTimerIndex(index)) == 0 ) { cascade(tv5, getTimerIndex(index)); } ++timerTick; tv1[index].replaceInit(workList); while (!workList.empty()) { TimerList timer = (TimerList)workList.firstEntry(); runningTimer = timer; if (timer.timerFunc != null) { timer.timerFunc.OnTimer(timer.param); } if (timer.timerAfterFunc != null) { timer.timerAfterFunc.OnTimerAfter(timer.param); } if (runningTimer != null) { switch (runningTimer.timerType) { case REPEAT: case FIXED: { if (timer.timerType == TimerType.FIXED) { ++timer.fixedTimerExecuteTimes; } modifyTimer(timer, timer.milli_seconds); } break; case DEADLINE: { detachTimer(timer); if (timer.attachEntry != null && !timer.attachEntry.empty()) { timer.attachEntry.delInit(); } addToFreeList(timer); } break; } } } } runningTimer = null; } public TimerList addDeadLineTimer(int expire_time, XParams param, ITimerFunc timer_func) { return addDeadLineTimer(expire_time, param, timer_func, null); } public TimerList addDeadLineTimer(int expire_time, XParams param, ITimerFunc timer_func, ITimerAfterFunc after_func) { TimerList timer = newTimerList(); timer.initTimerList(this, TimerType.DEADLINE, expire_time, param, timer_func, after_func); modifyTimer(timer, expire_time); return timer; } public TimerList addDeadLineTimerAndAttach(int expire_time, XParams param, ITimerFunc timer_func, TimerAttacher timer_attacher) { return addDeadLineTimerAndAttach(expire_time, param, timer_func, timer_attacher, null); } public TimerList addDeadLineTimerAndAttach(int expire_time, XParams param, ITimerFunc timer_func, TimerAttacher timer_attacher, ITimerAfterFunc after_func) { TimerList timer = addDeadLineTimer(expire_time, param, timer_func, after_func); timer_attacher.addTimer(timer.attachEntry); return timer; } public TimerList addRepeatTimer(int expire_time, XParams param, ITimerFunc timer_func) { TimerList timer = newTimerList(); timer.initTimerList(this, TimerType.REPEAT, expire_time, param, timer_func, null); modifyTimer(timer, expire_time); return timer; } public TimerList addFixedTimer(int expire_time, XParams param, ITimerFunc timer_func) { TimerList timer = newTimerList(); timer.initTimerList(this, TimerType.FIXED, expire_time, param, timer_func, null); modifyTimer(timer, expire_time); return timer; } public void modifyTimer(TimerList timer, int expire_time) { detachTimer(timer); if (timer.timerType == TimerType.FIXED) { long tick = System.currentTimeMillis(); int today_passed_seconds = SysUtils.now() - SysUtils.getDaySeconds(SysUtils.now(), 0); timer.expires = (tick - today_passed_seconds * 1000) + expire_time; if (timer.fixedTimerExecuteTimes > 0) { if (timer.expires <= tick) { timer.expires += 1000 * 3600 * 24; } } else { timer.expires = getTickCount.GetTickCount(content) + expire_time; } } timer.milli_seconds = expire_time; internalAddTimer(timer); } public TimerList getTimerByAttach(ListHead attach_entry) { return (TimerList)attach_entry.data; } public XParams getMutableParams(TimerList timer_list) { return timer_list.param; } public long getRemainTime(TimerList timer) { long remain_time = timer.expires - getTickCount.GetTickCount(content); return remain_time; } public TimerList getRunningTimer() { return runningTimer; } public int getIdleableMillSeconds() { int idle_time = 1; for (int lv1_idx = (int)(timerTick % TVR_MASK); lv1_idx < TVR_SIZE; ++lv1_idx) { if (!tv1[lv1_idx].empty()){ return idle_time <= 1 ? 1 : idle_time - 1; } ++idle_time; } return idle_time; } public void deleteTimer(TimerList timer_list) { if (timer_list.timerAfterFunc != null) { timer_list.timerAfterFunc.OnTimerAfter(timer_list.param); } detachTimer(timer_list); if (timer_list.attachEntry != null && !timer_list.attachEntry.empty()) { timer_list.attachEntry.del(); } addToFreeList(timer_list); } public void detachTimer(TimerList timer_list) { if (timer_list.entry != null && !timer_list.entry.empty()) { timer_list.entry.delInit(); } } private TimerList newTimerList() { return new TimerList(); } private void clear() { } private void addToFreeList(TimerList timer_list) { freeTimer.addTail(timer_list.entry); ++freeTimerNum; } private void gcTimerFunc() { } private int cascade(ListHead[] tv, int index) { tv[index].replaceInit(cascadeList); if (!cascadeList.empty()) { ListHead pos, n; for (pos = cascadeList.next, n = pos.next; pos != cascadeList; pos = n , n = pos.next) { internalAddTimer((TimerList)pos.data); } } cascadeList.init(); return index; } private final int getTimerIndex(int index) { return (int)((timerTick >> (TVR_BITS + index * TVN_BITS)) & TVN_MASK); } private final void internalAddTimer(TimerList timer) { long expires = timer.expires; long idx = expires - timerTick; ListHead vec; if (idx < 0) { vec = tv1[(int)(timerTick & TVR_MASK)]; } else if (idx < TVR_SIZE) { int i = (int)(expires & TVR_MASK); vec = tv1[i]; } else if (idx < (1 << (TVR_BITS + TVN_BITS))) { int i = (int)(expires >> TVR_BITS) & TVN_MASK; vec = tv2[i]; } else if (idx < (1 << (TVR_BITS + 2 * TVN_BITS))) { int i = (int)(expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK; vec = tv3[i]; } else if (idx < (1 << (TVR_BITS + 3 * TVN_BITS))) { int i = (int)(expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK; vec = tv4[i]; } else { int i = (int)(expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK; vec = tv5[i]; } vec.addTail(vec); } }