1
+ using System ;
2
+ using Whathecode . System . Collections . Generic ;
3
+
4
+
5
+ namespace Whathecode . System
6
+ {
7
+ public partial class AbstractInterval < T , TSize >
8
+ {
9
+ /// <summary>
10
+ /// Enumerator which allows you to walk across values inside an interval.
11
+ /// TODO: Having to pass the methods to operate on the generic type here is quite messy. Is there a better way around this?
12
+ /// </summary>
13
+ /// <typeparam name = "T">The type used to specify the interval, and used for the calculations.</typeparam>
14
+ /// <typeparam name = "TSize">The type used to specify distances in between two values of <see cref="T" />.</typeparam>
15
+ private class Enumerator : AbstractEnumerator < T >
16
+ {
17
+ readonly IInterval < T , TSize > _interval ;
18
+ readonly TSize _step ;
19
+ readonly Func < T , T , TSize > _subtract ;
20
+ readonly Func < T , TSize , T > _addSize ;
21
+ readonly Func < TSize , double > _convertSizeToDouble ;
22
+ readonly Func < double , TSize > _convertDoubleToSize ;
23
+ readonly Func < T , bool , T , bool , IInterval < T , TSize > > _createInstance ;
24
+
25
+ readonly bool _isAnchorSet ;
26
+ readonly T _anchor ;
27
+
28
+
29
+ /// <summary>
30
+ /// Create a new enumerator which traverses across an interval in specified steps.
31
+ /// </summary>
32
+ /// <param name = "interval">The interval which to traverse.</param>
33
+ /// <param name = "step">The steps to step forward each time.</param>
34
+ public Enumerator (
35
+ IInterval < T , TSize > interval , TSize step ,
36
+ Func < T , T , TSize > subtract ,
37
+ Func < T , TSize , T > addSize ,
38
+ Func < TSize , double > convertSizeToDouble ,
39
+ Func < double , TSize > convertDoubeToSize ,
40
+ Func < T , bool , T , bool , IInterval < T , TSize > > createInstance )
41
+ {
42
+ _interval = interval ;
43
+ _step = step ;
44
+ _subtract = subtract ;
45
+ _addSize = addSize ;
46
+ _convertSizeToDouble = convertSizeToDouble ;
47
+ _convertDoubleToSize = convertDoubeToSize ;
48
+ _createInstance = createInstance ;
49
+ }
50
+
51
+ public Enumerator (
52
+ IInterval < T , TSize > interval , TSize step ,
53
+ Func < T , T , TSize > subtract ,
54
+ Func < T , TSize , T > addSize ,
55
+ Func < TSize , double > convertSizeToDouble ,
56
+ Func < double , TSize > convertDoubeToSize ,
57
+ Func < T , bool , T , bool , IInterval < T , TSize > > createInstance ,
58
+ T anchorAt )
59
+ : this ( interval , step , subtract , addSize , convertSizeToDouble , convertDoubeToSize , createInstance )
60
+ {
61
+ _isAnchorSet = true ;
62
+ _anchor = anchorAt ;
63
+ }
64
+
65
+
66
+ protected override T GetFirst ( )
67
+ {
68
+ IInterval < T , TSize > interval = _interval ;
69
+
70
+ // When anchor is set, start the interval at the next anchor position.
71
+ if ( _isAnchorSet )
72
+ {
73
+ TSize anchorDiff = _subtract ( _interval . Start , _anchor ) ;
74
+ double stepSize = _convertSizeToDouble ( _step ) ;
75
+ double diff = Math . Abs ( _convertSizeToDouble ( anchorDiff ) ) % stepSize ;
76
+ if ( diff > 0 )
77
+ {
78
+ if ( _anchor . CompareTo ( _interval . Start ) < 0 )
79
+ {
80
+ diff = stepSize - diff ;
81
+ }
82
+ TSize addition = _convertDoubleToSize ( diff ) ;
83
+ interval = _createInstance (
84
+ _addSize ( _interval . Start , addition ) , true ,
85
+ _interval . End , _interval . IsEndIncluded ) ;
86
+ }
87
+ }
88
+
89
+ // When first value doesn't lie in interval, immediately step.
90
+ return interval . IsStartIncluded ? interval . Start : _addSize ( interval . Start , _step ) ;
91
+ }
92
+
93
+ protected override T GetNext ( int enumeratedAlready , T previous )
94
+ {
95
+ return _addSize ( previous , _step ) ;
96
+ }
97
+
98
+ protected override bool HasElements ( )
99
+ {
100
+ bool nextInInterval = _interval . LiesInInterval ( _addSize ( _interval . Start , _step ) ) ;
101
+ return _interval . IsStartIncluded || nextInInterval ;
102
+ }
103
+
104
+ protected override bool HasMoreElements ( int enumeratedAlready , T previous )
105
+ {
106
+ if ( _convertSizeToDouble ( _step ) == 0 && enumeratedAlready == 1 )
107
+ {
108
+ return false ;
109
+ }
110
+
111
+ return _interval . LiesInInterval ( _addSize ( previous , _step ) ) ;
112
+ }
113
+
114
+ public override void Dispose ( )
115
+ {
116
+ // TODO: Nothing to do?
117
+ }
118
+ }
119
+ }
120
+ }
0 commit comments