forked from QuantConnect/pythonnet
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathEnumObject.cs
More file actions
218 lines (190 loc) · 7.39 KB
/
EnumObject.cs
File metadata and controls
218 lines (190 loc) · 7.39 KB
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
using System;
using System.Runtime.CompilerServices;
namespace Python.Runtime
{
/// <summary>
/// Managed class that provides the implementation for reflected enum types.
/// </summary>
[Serializable]
internal class EnumObject : ClassBase
{
internal EnumObject(Type type) : base(type)
{
}
/// <summary>
/// Standard comparison implementation for instances of enum types.
/// </summary>
public static NewReference tp_richcompare(BorrowedReference ob, BorrowedReference other, int op)
{
object rightInstance;
CLRObject leftClrObject;
int comparisonResult;
switch (op)
{
case Runtime.Py_EQ:
case Runtime.Py_NE:
var pytrue = Runtime.PyTrue;
var pyfalse = Runtime.PyFalse;
// swap true and false for NE
if (op != Runtime.Py_EQ)
{
pytrue = Runtime.PyFalse;
pyfalse = Runtime.PyTrue;
}
if (ob == other)
{
return new NewReference(pytrue);
}
if (!TryGetSecondCompareOperandInstance(ob, other, out leftClrObject, out rightInstance))
{
return new NewReference(pyfalse);
}
if (rightInstance != null &&
TryCompare(leftClrObject.inst as Enum, rightInstance, out comparisonResult) &&
comparisonResult == 0)
{
return new NewReference(pytrue);
}
else
{
return new NewReference(pyfalse);
}
case Runtime.Py_LT:
case Runtime.Py_LE:
case Runtime.Py_GT:
case Runtime.Py_GE:
if (!TryGetSecondCompareOperandInstance(ob, other, out leftClrObject, out rightInstance))
{
return Exceptions.RaiseTypeError("Cannot get managed object");
}
if (rightInstance == null)
{
return Exceptions.RaiseTypeError($"Cannot compare {leftClrObject.inst.GetType()} to None");
}
try
{
if (!TryCompare(leftClrObject.inst as Enum, rightInstance, out comparisonResult))
{
return Exceptions.RaiseTypeError($"Cannot compare {leftClrObject.inst.GetType()} with {rightInstance.GetType()}");
}
return new NewReference(GetComparisonResult(op, comparisonResult));
}
catch (ArgumentException e)
{
return Exceptions.RaiseTypeError(e.Message);
}
default:
return new NewReference(Runtime.PyNotImplemented);
}
}
/// <summary>
/// Tries comparing the give enum to the right operand by converting it to the appropriate type if possible
/// </summary>
/// <returns>True if the right operand was converted to a supported type and the comparison was performed successfully</returns>
private static bool TryCompare(Enum left, object right, out int result)
{
result = int.MinValue;
var conversionSuccessful = true;
var leftType = left.GetType();
var rightType = right.GetType();
// Same enum comparison:
if (leftType == rightType)
{
result = left.CompareTo(right);
}
// Comparison with other enum types
else if (rightType.IsEnum)
{
var leftIsUnsigned = leftType.GetEnumUnderlyingType() == typeof(UInt64);
result = Compare(left, right as Enum, leftIsUnsigned);
}
else if (right is string rightString)
{
result = left.ToString().CompareTo(rightString);
}
else
{
var leftIsUnsigned = leftType.GetEnumUnderlyingType() == typeof(UInt64);
switch (right)
{
case double rightDouble:
result = Compare(left, rightDouble, leftIsUnsigned);
break;
case long rightLong:
result = Compare(left, rightLong, leftIsUnsigned);
break;
case ulong rightULong:
result = Compare(left, rightULong, leftIsUnsigned);
break;
case int rightInt:
result = Compare(left, (long)rightInt, leftIsUnsigned);
break;
case uint rightUInt:
result = Compare(left, (ulong)rightUInt, leftIsUnsigned);
break;
default:
conversionSuccessful = false;
break;
}
}
return conversionSuccessful;
}
#region Comparison against integers
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int Compare(long a, ulong b)
{
if (a < 0) return -1;
return ((ulong)a).CompareTo(b);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int Compare(Enum a, long b, bool isUnsigned)
{
if (isUnsigned)
{
return -Compare(b, Convert.ToUInt64(a));
}
return Convert.ToInt64(a).CompareTo(b);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int Compare(Enum a, ulong b, bool inUnsigned)
{
if (inUnsigned)
{
return Convert.ToUInt64(a).CompareTo(b);
}
return Compare(Convert.ToInt64(a), b);
}
#endregion
#region Comparison against doubles
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int Compare(Enum a, double b, bool isUnsigned)
{
if (isUnsigned)
{
var uIntA = Convert.ToUInt64(a);
if (uIntA < b) return -1;
if (uIntA > b) return 1;
return 0;
}
var intA = Convert.ToInt64(a);
if (intA < b) return -1;
if (intA > b) return 1;
return 0;
}
#endregion
#region Comparison against other enum types
/// <summary>
/// We support comparing enums of different types by comparing their underlying values.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int Compare(Enum a, Enum b, bool isUnsigned)
{
if (b.GetType().GetEnumUnderlyingType() == typeof(UInt64))
{
return Compare(a, Convert.ToUInt64(b), isUnsigned);
}
return Compare(a, Convert.ToInt64(b), isUnsigned);
}
#endregion
}
}