-
Notifications
You must be signed in to change notification settings - Fork 9
/
EnumTraverseExtension.cs
142 lines (138 loc) · 6.52 KB
/
EnumTraverseExtension.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* --------------------------------------------------------------------------------
* Gear: Parallax Inc. Propeller P1 Emulator
* Copyright 2007-2022 - Gear Developers
* --------------------------------------------------------------------------------
* EnumTraverseExtension.cs
* --------------------------------------------------------------------------------
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* --------------------------------------------------------------------------------
*/
using System;
using System.Diagnostics;
// ReSharper disable ExceptionNotDocumented
namespace Gear.Utils
{
/// <summary>Global extension to traverse Enums.</summary>
/// <remarks>To help on detection of duplicates values, both methods try
/// assertions of this on debug, showing an alert message.<br/>
/// Based on
/// https://stackoverflow.com/questions/642542/how-to-get-next-or-previous-enum-value-in-c-sharp </remarks>
/// @version v22.09.02 - Added.
public static class EnumTraverseExtension
{
/// <summary>Get the next value of enum.</summary>
/// <remarks>Requirements for Enum values:<br/>
/// - A sub range of values of the enum can be used for first and last
/// values.<br/>
/// - Duplicated values should be avoided.
/// - Negatives values produce unexpected order changes. Avoid it.<br/>
/// Allowed characteristics for Enum values:<br/>
/// - Values don't have to be consecutive: flag enum style is
/// correctly managed.</remarks>
/// <typeparam name="TEnum">Enum type to be traverse.</typeparam>
/// <param name="startValue">Enum value of <typeparamref name="TEnum"/>
/// to start.</param>
/// <param name="rollOver">TRUE signals the <paramref name="startValue"/>
/// is the last in Enum, so the first one is returned, rolling over
/// the values; FALSE indicates no rolling over.</param>
/// <returns>The next value, if <paramref name="startValue"/> parameter
/// is not the last. If it would be the last value of enum, this method
/// returns the first, signaling this situation in
/// <paramref name="rollOver"/> parameter this situation.</returns>
/// <exception cref="ArgumentException">When <typeparamref name="TEnum"/>
/// type is not an Enum type.</exception>
public static TEnum EnumNext<TEnum>(this TEnum startValue, out bool rollOver)
where TEnum : Enum
{
if (!typeof(TEnum).IsEnum)
throw new ArgumentException(
$"Argument {typeof(TEnum).FullName} is not an Enum.");
TEnum[] arr = (TEnum[])Enum.GetValues(startValue.GetType());
int lastIndex = Array.LastIndexOf(arr, startValue) + 1;
#if DEBUG
int firstIndex = Array.IndexOf(arr, startValue) + 1;
if (firstIndex != lastIndex)
{
string msg = $"First position: {firstIndex - 1:D}\n" +
$"Last position : {lastIndex - 1:D}\n";
Debug.Assert(false,
$"Duplicated enum values detected on {typeof(TEnum)} Enum:\n",
msg);
}
#endif
if (arr.Length == lastIndex)
{
rollOver = true;
return arr[0];
}
else
{
rollOver = false;
return arr[lastIndex];
}
}
/// <summary>Get the previous value of enum.</summary>
/// <remarks>Requirements for Enum values:<br/>
/// - A sub range of values of the enum can be used for first and last
/// values.<br/>
/// - Duplicated values should be avoided.
/// - Negatives values produce unexpected order changes. Avoid it.<br/>
/// Allowed characteristics for Enum values:<br/>
/// - Values don't have to be consecutive: flag enum style is
/// correctly managed.</remarks>
/// <typeparam name="TEnum">Enum type to be traverse.</typeparam>
/// <param name="startValue">Enum value of <typeparamref name="TEnum"/>
/// to start.</param>
/// <param name="rollOver">TRUE signals the <paramref name="startValue"/>
/// is the first in Enum, so the last one is returned, rolling over
/// the values; FALSE indicates no rolling over.</param>
/// <returns>The previous value, if <paramref name="startValue"/>
/// parameter is not the first. If it would be the first value of enum,
/// this method returns the last, signaling this situation in
/// <paramref name="rollOver"/> parameter.</returns>
/// <exception cref="ArgumentException">When <typeparamref name="TEnum"/>
/// type is not an Enum type.</exception>
public static TEnum EnumPrev<TEnum>(this TEnum startValue, out bool rollOver)
where TEnum : Enum
{
if (!typeof(TEnum).IsEnum)
throw new ArgumentException(
$"Argument {typeof(TEnum).FullName} is not an Enum.");
TEnum[] arr = (TEnum[])Enum.GetValues(startValue.GetType());
int firstIndex = Array.IndexOf(arr, startValue) - 1;
#if DEBUG
int lastIndex = Array.LastIndexOf(arr, startValue) + 1;
if (firstIndex != lastIndex)
{
string msg = $"First position: {firstIndex - 1:D}\n" +
$"Last position : {lastIndex - 1:D}\n";
Debug.Assert(false,
$"Duplicated enum values detected on {typeof(TEnum)} Enum:\n",
msg);
}
#endif
if (firstIndex < 0)
{
rollOver = true;
return arr[arr.Length - 1];
}
else
{
rollOver = false;
return arr[firstIndex];
}
}
}
}