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 }