1 module auxil.cursor;
2 
3 import std.math : isNaN;
4 
5 struct Cursor
6 {
7 	alias Type = int;
8 	/// defines direction of traversing
9 	enum Order : bool { backward, forward, }
10 
11 	// sum of all previous elements
12 	// it can have only fixed set of values so it is called `fixed`
13 	Type fixedPosition;
14 	// the value we should iterate over given sequence and
15 	// can be any value
16 	private Type _destination;
17 	// the start position
18 	Type init_value;
19 	Type last_value;
20 	Type current_value;
21 
22 	this(Type v) @safe @nogc
23 	{
24 		reset(v);
25 	}
26 
27 	void reset(Type v = 0) @safe @nogc
28 	{
29 		fixedPosition = 0;
30 		_destination  = 0;
31 		init_value    = v;
32 		last_value    = 0;
33 		current_value = 0;
34 	}
35 
36 	void scroll(Type value) @safe @nogc
37 	{
38 		assert(value >= 0);
39 		_destination = fixedPosition + value;
40 	}
41 
42 	auto phase() @safe @nogc const
43 	{
44 		return _destination - fixedPosition;
45 	}
46 
47 	// used if the sequence has ended before
48 	// the destination was achieved
49 	// because the current position is 
50 	// the position of the next elements, i.e.
51 	// non-existing element because the sequence
52 	// has ended
53 	//
54 	// the reason is that there is no way to get know
55 	// if the current element is the last one
56 	auto fixUp() @safe @nogc
57 	{
58 		// if processing was not completed it
59 		// means the fixed position belongs to the next
60 		// element after the last one so correct this
61 		if (!_complete)
62 			fixedPosition -= last_value;
63 	}
64 
65 	private bool _complete;
66 	bool complete() @safe @nogc { return _complete; }
67 
68 	void begin(Type v) @safe @nogc
69 	{
70 		current_value = v;
71 debug {
72 	import std;
73 	writeln(current_value);
74 }
75 	}
76 
77 	void next(Type v) @safe @nogc
78 	{
79 		if (fixedPosition + v > _destination)
80 		{
81 			_complete = true;
82 		}
83 		else
84 		{
85 			last_value = v;
86 			fixedPosition += last_value;
87 		}
88 	}
89 
90 	void toString(Writer)(ref Writer w) @safe
91 	{
92 		import std.algorithm : copy;
93 		import std.conv : text;
94 		typeof(this).stringof.copy(w);
95 		w.put('(');
96 		static foreach(i; 0..this.tupleof.length)
97 		{{
98 			enum name = __traits(identifier, this.tupleof[i]);
99 			text(name, " : ", this.tupleof[i], ", ").copy(w);
100 		}}
101 		w.put(')');
102 	}
103 
104 	package auto calcPosition(Order order)() @safe @nogc
105 	{
106 		static if (order == Cursor.Order.forward)
107 			return init_value + fixedPosition;
108 		else
109 			return init_value - fixedPosition - current_value;
110 	}
111 }