1 /**
2 * Copyright © DiamondMVC 2018
3 * License: MIT (https://github.com/DiamondMVC/Diamond/blob/master/LICENSE)
4 * Author: Jacob Jensen (bausshf)
5 */
6 module diamond.data.snapshot;
7 
8 import std.traits : isScalarType;
9 
10 /// Wrapper for a snapshot type, which is a type that keeps track of a type's value history.
11 final class Snapshot(T)
12 if (is(T == struct) || isScalarType!T)
13 {
14 	private:
15   /// The values.
16 	T[] _values;
17   /// The current value.
18 	T _current;
19 
20 	public:
21 	final:
22   /// Creates a new snapshot of a type.
23 	this() { }
24 
25   /**
26   * Creates a new snapshot of a type.
27   * Params:
28   *   initValue = The initializationValue
29   */
30 	this(T initValue)
31 	{
32 		value = initValue;
33 	}
34 
35 	@property
36 	{
37     /// Sets the value.
38 		void value(T newValue)
39 		{
40 			_values ~= newValue;
41 			_current = newValue;
42 		}
43 
44     /// Gets the value.
45 		T value()
46 		{
47 			if (!_values || !_values.length)
48 			{
49 				return T.init;
50 			}
51 
52 			return _current;
53 		}
54 	}
55 
56   /// Rolls back to the previous value.
57 	void prev()
58 	{
59 		if (!_values || !_values.length)
60 		{
61 			return;
62 		}
63 
64 		_values = _values[0 .. $-1];
65 		_current = _values[$-1];
66 	}
67 
68   /**
69   * Rolls back a specific amount of states.
70   * Params:
71   *   states = The amount of states to roll back.
72   */
73 	void prev(size_t states)
74 	{
75 		if (states >= _values.length)
76 		{
77 			_values = [];
78 			_current = T.init;
79 		}
80 		else
81 		{
82 			_values = _values[0 .. $-states];
83 			_current = _values[$-1];
84 		}
85 	}
86 
87   /// Resets the value to its first known value.
88 	void reset()
89 	{
90 		if (!_values || !_values.length)
91 		{
92 			return;
93 		}
94 
95 		_values = [_values[0]];
96 	}
97 
98   /**
99   * Operator overload for indexing to retrieve a specific historical snapshot of the type.
100   * Params:
101   *   index = The index to retrieve the snapshot of.
102   * Returns:
103   *   The value at the index if found, T.init otherwise.
104   */
105 	T opIndex(size_t index)
106 	{
107 		if (index >= _values.length)
108 		{
109 			return T.init;
110 		}
111 
112 		return _values[index];
113 	}
114 
115 	static if (isScalarType!T)
116 	{
117     /// Operator overload for comparing scalar types.
118 		int opCmp(T comparison)
119 		{
120 			if (_current < comparison)
121 			{
122 				return -1;
123 			}
124 
125 			if (_current > comparison)
126 			{
127 				return 1;
128 			}
129 
130 			return 0;
131 		}
132 
133     /// Operator overload for equality comparison between scalar types.
134 		bool opEquals(T comparison)
135 		{
136 			return opCmp(comparison) == 0;
137 		}
138 	}
139 
140   /// Alias this to set the value directly for the snapshot.
141 	alias value this;
142 }