Blame mono/Assistance/KeyHistory.cs

Ivan Mahonin a6a507
using System;
Ivan Mahonin a6a507
using System.Collections.Generic;
Ivan Mahonin a6a507
Ivan Mahonin a6a507
namespace Assistance {
Ivan Mahonin a6a507
	public class KeyHistory<T> where T: IComparable, new() {
Ivan Mahonin a6a507
		public class Holder: IDisposable {
Ivan Mahonin a6a507
			public readonly KeyHistory<T> history;
Ivan Mahonin a6a507
			public readonly long ticks;
Ivan Mahonin a6a507
			public readonly double timeOffset;
Ivan Mahonin a6a507
Ivan Mahonin a6a507
			private readonly long heldTicks;
Ivan Mahonin a6a507
			private bool disposed = false;
Ivan Mahonin a6a507
Ivan Mahonin a6a507
			public Holder(KeyHistory<T> history, long ticks, double timeOffset = 0.0) {
Ivan Mahonin a6a507
				this.history = history;
Ivan Mahonin a6a507
				this.ticks = ticks;
Ivan Mahonin a6a507
				this.timeOffset = timeOffset;
Ivan Mahonin a6a507
				heldTicks = history.hold(ticks);
Ivan Mahonin a6a507
			}
Ivan Mahonin a6a507
			
Ivan Mahonin a62e15
			public Holder offset(double timeOffset) {
Ivan Mahonin a62e15
				return Geometry.isEqual(timeOffset, 0.0)
Ivan Mahonin a62e15
				     ? this
Ivan Mahonin a62e15
				     : new Holder(history, ticks, this.timeOffset + timeOffset);
Ivan Mahonin a62e15
			}
Ivan Mahonin a62e15
			
Ivan Mahonin a6a507
			public KeyState<T>.Holder get(double time) {
Ivan Mahonin a6a507
				long dticks = (long)Math.Ceiling(Timer.frequency*(time + timeOffset));
Ivan Mahonin a6a507
				KeyState<T> state = history.get(ticks + dticks);
Ivan Mahonin a6a507
				return new KeyState<T>.Holder(state, ticks, timeOffset + time);
Ivan Mahonin a6a507
			}
Ivan Mahonin a6a507
Ivan Mahonin a6a507
			public void Dispose() { 
Ivan Mahonin a6a507
				Dispose(true);
Ivan Mahonin a6a507
				GC.SuppressFinalize(this);           
Ivan Mahonin a6a507
			}
Ivan Mahonin a6a507
			
Ivan Mahonin a6a507
			protected virtual void Dispose(bool disposing) {
Ivan Mahonin a6a507
				if (disposed) return;
Ivan Mahonin a6a507
				history.release(heldTicks);
Ivan Mahonin a6a507
				disposed = true;
Ivan Mahonin a6a507
			}
Ivan Mahonin a6a507
			
Ivan Mahonin a6a507
			~Holder()
Ivan Mahonin a6a507
				{ Dispose(false); }
Ivan Mahonin a6a507
		}
Ivan Mahonin a6a507
	
Ivan Mahonin a6a507
		private readonly List<KeyState<T>> states = new List<KeyState<T>>() { new KeyState<T>() };
Ivan Mahonin a6a507
		private readonly List<long> locks = new List<long>();
Ivan Mahonin a6a507
		
Ivan Mahonin a6a507
		public KeyState<T> current
Ivan Mahonin a6a507
			{ get { return states[ states.Count - 1 ]; } }
Ivan Mahonin a6a507
		
Ivan Mahonin 589f9a
		public KeyState<T> change(bool press, T value, long ticks)	{
Ivan Mahonin a6a507
			states.Add(current.change(press, value, ticks));
Ivan Mahonin a6a507
			autoRemove();
Ivan Mahonin 589f9a
			return current;
Ivan Mahonin a6a507
		}
Ivan Mahonin a6a507
		public KeyState<T> press(T value, long ticks)
Ivan Mahonin a6a507
			{ return change(true, value, ticks); }
Ivan Mahonin a6a507
		public KeyState<T> release(T value, long ticks)
Ivan Mahonin a6a507
			{ return change(false, value, ticks); }
Ivan Mahonin a6a507
		
Ivan Mahonin a6a507
		private int findLock(long ticks) {
Ivan Mahonin a6a507
			// locks[a] <= ticks < locks[b]
Ivan Mahonin 0f2bf8
			if (locks.Count == 0) return -1;
Ivan Mahonin a6a507
			int a = 0;
Ivan Mahonin 0f2bf8
			int b = locks.Count - 1;
Ivan Mahonin 589f9a
			if (locks[a] < ticks) return -1;
Ivan Mahonin a6a507
			if (ticks >= locks[b]) return b;
Ivan Mahonin 589f9a
			while(true) {
Ivan Mahonin a6a507
				int c = (a + b)/2;
Ivan Mahonin a6a507
				if (a == c) break;
Ivan Mahonin a6a507
				if (ticks < locks[c]) b = c; else a = c;
Ivan Mahonin a6a507
			}
Ivan Mahonin a6a507
			return a;
Ivan Mahonin a6a507
		}
Ivan Mahonin a6a507
		
Ivan Mahonin a6a507
		private void autoRemove() {
Ivan Mahonin a6a507
			long ticks = locks.Count > 0 ? locks[0] : long.MaxValue;
Ivan Mahonin a6a507
			while(states.Count > 1 && (states[0].ticks < ticks || states[0].isEmpty))
Ivan Mahonin a6a507
				states.RemoveAt(0);
Ivan Mahonin a6a507
		}
Ivan Mahonin a6a507
		
Ivan Mahonin a6a507
		private long hold(long ticks) {
Ivan Mahonin a62e15
			long heldTicks = Math.Max(ticks, states[0].ticks);
Ivan Mahonin a6a507
			locks.Insert(findLock(heldTicks) + 1, heldTicks);
Ivan Mahonin a6a507
			return heldTicks;
Ivan Mahonin a6a507
		}
Ivan Mahonin a6a507
		
Ivan Mahonin a6a507
		private void release(long heldTicks) {
Ivan Mahonin a6a507
			int i = findLock(heldTicks);
Ivan Mahonin a6a507
			if (i >= 0 && locks[i] == heldTicks) locks.RemoveAt(i);
Ivan Mahonin a6a507
			autoRemove();
Ivan Mahonin a6a507
		}
Ivan Mahonin a6a507
		
Ivan Mahonin a6a507
		private KeyState<T> get(long ticks) {
Ivan Mahonin a6a507
			// state[a].ticks <= ticks < state[b].ticks 
Ivan Mahonin a6a507
			int a = 0;
Ivan Mahonin a6a507
			int b = states.Count - 1;
Ivan Mahonin a6a507
			if (states[a].ticks < ticks) return new KeyState<T>();
Ivan Mahonin 589f9a
			if (ticks >= states[b].ticks) return states[b];
Ivan Mahonin 589f9a
			while(true) {
Ivan Mahonin a6a507
				int c = (a + b)/2;
Ivan Mahonin a6a507
				if (a == c) break;
Ivan Mahonin a6a507
				if (ticks < states[c].ticks) b = c; else a = c;
Ivan Mahonin a6a507
			}
Ivan Mahonin a6a507
			return states[a];
Ivan Mahonin a6a507
		}
Ivan Mahonin a6a507
	}
Ivan Mahonin a6a507
}
Ivan Mahonin a6a507