FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
pythonnet/src/runtime/Types/OperatorMethod.cs at v3.2.0-rc1 · pythonnet/pythonnet · GitHub
pythonnet
pythonnet
Repository navigation
Code
Issues
147
(147)
Pull requests
11
(11)
Discussions
Actions
Projects
Wiki
Security and quality
Insights
Expand file tree
Breadcrumbs
pythonnet
/
src
/
runtime
/
Types
/
OperatorMethod.cs
Copy path
More file actions
More file actions
Latest commit
History
History
History
206 lines (187 loc) · 8.11 KB
Breadcrumbs
pythonnet
/
src
/
runtime
/
Types
/
OperatorMethod.cs
Copy path
File metadata and controls
206 lines (187 loc) · 8.11 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
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
using
System
;
using
System
.
Collections
.
Generic
;
using
System
.
Diagnostics
;
using
System
.
Linq
;
using
System
.
Reflection
;
using
System
.
Text
;
namespace
Python
.
Runtime
{
internal
static
class
OperatorMethod
{
/// <summary>
/// Maps the compiled method name in .NET CIL (e.g. op_Addition) to
/// the equivalent Python operator (e.g. __add__) as well as the offset
/// that identifies that operator's slot (e.g. nb_add) in heap space.
/// </summary>
public
static
Dictionary
<
string
,
SlotDefinition
>
OpMethodMap
{
get
;
private
set
;
}
public
static
Dictionary
<
string
,
string
>
ComparisonOpMap
{
get
;
private
set
;
}
public
readonly
struct
SlotDefinition
{
public
SlotDefinition
(
string
methodName
,
int
typeOffset
)
{
MethodName
=
methodName
;
TypeOffset
=
typeOffset
;
}
public
string
MethodName
{
get
;
}
public
int
TypeOffset
{
get
;
}
}
private
static
PyObject
?
_opType
;
static
OperatorMethod
(
)
{
// .NET operator method names are documented at:
// https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/operator-overloads
// Python operator methods and slots are documented at:
// https://docs.python.org/3/c-api/typeobj.html
// TODO: Rich compare, inplace operator support
OpMethodMap
=
new
Dictionary
<
string
,
SlotDefinition
>
{
[
"op_Addition"
]
=
new
SlotDefinition
(
"__add__"
,
TypeOffset
.
nb_add
)
,
[
"op_Subtraction"
]
=
new
SlotDefinition
(
"__sub__"
,
TypeOffset
.
nb_subtract
)
,
[
"op_Multiply"
]
=
new
SlotDefinition
(
"__mul__"
,
TypeOffset
.
nb_multiply
)
,
[
"op_Division"
]
=
new
SlotDefinition
(
"__truediv__"
,
TypeOffset
.
nb_true_divide
)
,
[
"op_Modulus"
]
=
new
SlotDefinition
(
"__mod__"
,
TypeOffset
.
nb_remainder
)
,
[
"op_BitwiseAnd"
]
=
new
SlotDefinition
(
"__and__"
,
TypeOffset
.
nb_and
)
,
[
"op_BitwiseOr"
]
=
new
SlotDefinition
(
"__or__"
,
TypeOffset
.
nb_or
)
,
[
"op_ExclusiveOr"
]
=
new
SlotDefinition
(
"__xor__"
,
TypeOffset
.
nb_xor
)
,
[
"op_LeftShift"
]
=
new
SlotDefinition
(
"__lshift__"
,
TypeOffset
.
nb_lshift
)
,
[
"op_RightShift"
]
=
new
SlotDefinition
(
"__rshift__"
,
TypeOffset
.
nb_rshift
)
,
[
"op_OnesComplement"
]
=
new
SlotDefinition
(
"__invert__"
,
TypeOffset
.
nb_invert
)
,
[
"op_UnaryNegation"
]
=
new
SlotDefinition
(
"__neg__"
,
TypeOffset
.
nb_negative
)
,
[
"op_UnaryPlus"
]
=
new
SlotDefinition
(
"__pos__"
,
TypeOffset
.
nb_positive
)
,
[
"__int__"
]
=
new
SlotDefinition
(
"__int__"
,
TypeOffset
.
nb_int
)
,
[
"__float__"
]
=
new
SlotDefinition
(
"__float__"
,
TypeOffset
.
nb_float
)
,
[
"__index__"
]
=
new
SlotDefinition
(
"__index__"
,
TypeOffset
.
nb_index
)
,
}
;
ComparisonOpMap
=
new
Dictionary
<
string
,
string
>
{
[
"op_Equality"
]
=
"__eq__"
,
[
"op_Inequality"
]
=
"__ne__"
,
[
"op_LessThanOrEqual"
]
=
"__le__"
,
[
"op_GreaterThanOrEqual"
]
=
"__ge__"
,
[
"op_LessThan"
]
=
"__lt__"
,
[
"op_GreaterThan"
]
=
"__gt__"
,
}
;
}
public
static
void
Initialize
(
)
{
_opType
=
GetOperatorType
(
)
;
}
public
static
void
Shutdown
(
)
{
if
(
_opType
!=
null
)
{
_opType
.
Dispose
(
)
;
_opType
=
null
;
}
}
public
static
bool
IsOperatorMethod
(
MethodBase
method
)
{
if
(
!
method
.
IsSpecialName
&&
!
method
.
IsOpsHelper
(
)
)
{
return
false
;
}
return
OpMethodMap
.
ContainsKey
(
method
.
Name
)
||
ComparisonOpMap
.
ContainsKey
(
method
.
Name
)
;
}
public
static
bool
IsComparisonOp
(
MethodBase
method
)
{
return
ComparisonOpMap
.
ContainsKey
(
method
.
Name
)
;
}
/// <summary>
/// For the operator methods of a CLR type, set the special slots of the
/// corresponding Python type's operator methods.
/// </summary>
public
static
void
FixupSlots
(
BorrowedReference
pyType
,
Type
clrType
)
{
Debug
.
Assert
(
_opType
!=
null
)
;
var
operatorCandidates
=
GetOperatorCandidates
(
clrType
)
;
foreach
(
var
method
in
operatorCandidates
)
{
// We only want to override slots for operators excluding
// comparison operators, which are handled by ClassBase.tp_richcompare.
if
(
!
OpMethodMap
.
ContainsKey
(
method
.
Name
)
)
{
continue
;
}
int
offset
=
OpMethodMap
[
method
.
Name
]
.
TypeOffset
;
// Copy the default implementation of e.g. the nb_add slot,
// which simply calls __add__ on the type.
IntPtr
func
=
Util
.
ReadIntPtr
(
_opType
!
,
offset
)
;
// Write the slot definition of the target Python type, so
// that we can later modify __add___ and it will be called
// when used with a Python operator.
// https://tenthousandmeters.com/blog/python-behind-the-scenes-6-how-python-object-system-works/
Util
.
WriteIntPtr
(
pyType
,
offset
,
func
)
;
}
}
static
IEnumerable
<
MethodInfo
>
GetOperatorCandidates
(
Type
clrType
)
{
const
BindingFlags
flags
=
BindingFlags
.
Public
|
BindingFlags
.
Static
;
if
(
clrType
.
IsEnum
)
{
return
typeof
(
EnumOps
<
>
)
.
MakeGenericType
(
clrType
)
.
GetMethods
(
flags
)
.
Concat
(
typeof
(
FlagEnumOps
<
>
)
.
MakeGenericType
(
clrType
)
.
GetMethods
(
flags
)
)
;
}
return
clrType
.
GetMethods
(
flags
)
;
}
public
static
string
GetPyMethodName
(
string
clrName
)
{
if
(
OpMethodMap
.
ContainsKey
(
clrName
)
)
{
return
OpMethodMap
[
clrName
]
.
MethodName
;
}
else
{
return
ComparisonOpMap
[
clrName
]
;
}
}
private
static
string
GenerateDummyCode
(
)
{
var
sb
=
new
StringBuilder
(
)
;
sb
.
AppendLine
(
"class OperatorMethod(object):"
)
;
foreach
(
var
item
in
OpMethodMap
.
Values
)
{
string
def
=
string
.
Format
(
" def {0}(self, other): pass"
,
item
.
MethodName
)
;
sb
.
AppendLine
(
def
)
;
}
return
sb
.
ToString
(
)
;
}
private
static
PyObject
GetOperatorType
(
)
{
using
var
locals
=
new
PyDict
(
)
;
// A hack way for getting typeobject.c::slotdefs
string
code
=
GenerateDummyCode
(
)
;
// The resulting OperatorMethod class is stored in a PyDict.
PythonEngine
.
Exec
(
code
,
null
,
locals
)
;
// Return the class itself, which is a type.
return
locals
.
GetItem
(
"OperatorMethod"
)
;
}
public
static
string
ReversePyMethodName
(
string
pyName
)
{
return
pyName
.
Insert
(
2
,
"r"
)
;
}
/// <summary>
/// Check if the method should have a reversed operation.
/// </summary>
/// <param name="method">The operator method.</param>
/// <returns></returns>
public
static
bool
HaveReverse
(
MethodBase
method
)
{
var
pi
=
method
.
GetParameters
(
)
;
return
OpMethodMap
.
ContainsKey
(
method
.
Name
)
&&
pi
.
Length
==
2
;
}
public
static
void
FilterMethods
(
MethodBase
[
]
methods
,
out
MethodBase
[
]
forwardMethods
,
out
MethodBase
[
]
reverseMethods
)
{
var
forwardMethodsList
=
new
List
<
MethodBase
>
(
)
;
var
reverseMethodsList
=
new
List
<
MethodBase
>
(
)
;
foreach
(
var
method
in
methods
)
{
forwardMethodsList
.
Add
(
method
)
;
if
(
HaveReverse
(
method
)
)
{
reverseMethodsList
.
Add
(
method
)
;
}
}
forwardMethods
=
forwardMethodsList
.
ToArray
(
)
;
reverseMethods
=
reverseMethodsList
.
ToArray
(
)
;
}
}
}
Back
|
FazBrowse Home
|
New Git URL