Blame mono/Assistance/KeyHistory.cs

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