/
mops.py
174 lines (114 loc) · 3.38 KB
/
mops.py
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
"""
Math operations, e.g. for arbitrary precision integers
They are currently int64_t, rather than C int, but we want to upgrade to
heap-allocated integers.
Regular int ops can use the normal operators + - * /, or maybe i_add() if we
really want. Does that make code gen harder or worse?
Float ops could be + - * / too, but it feels nicer to develop a formal
interface?
"""
from __future__ import print_function
class BigInt(object):
def __init__(self, i):
# type: (int) -> None
self.i = i
# Prevent possible mistakes. Could do this with other operators
def __eq__(self, other):
# type: (object) -> bool
raise AssertionError('Use mops.Equal()')
def __gt__(self, other):
# type: (object) -> bool
raise AssertionError('Use functions in mops.py')
def __ge__(self, other):
# type: (object) -> bool
raise AssertionError('Use functions in mops.py')
ZERO = BigInt(0)
ONE = BigInt(1)
MINUS_ONE = BigInt(-1)
def ToStr(b):
# type: (BigInt) -> str
return str(b.i)
def FromStr(s, base=10):
# type: (str, int) -> BigInt
return BigInt(int(s, base))
def BigTruncate(b):
# type: (BigInt) -> int
"""Only truncates in C++"""
return b.i
def IntWiden(i):
# type: (int) -> BigInt
"""Only widens in C++"""
return BigInt(i)
def FromC(i):
# type: (int) -> BigInt
"""A no-op in C, for RLIM_INFINITY"""
return BigInt(i)
def FromBool(b):
# type: (bool) -> BigInt
"""Only widens in C++"""
return BigInt(1) if b else BigInt(0)
def ToFloat(b):
# type: (BigInt) -> float
"""Used by float(42) in Oils"""
return float(b.i)
def FromFloat(f):
# type: (float) -> BigInt
"""Used by int(3.14) in Oils"""
return BigInt(int(f))
# Can't use operator overloading
def Negate(b):
# type: (BigInt) -> BigInt
return BigInt(-b.i)
def Add(a, b):
# type: (BigInt, BigInt) -> BigInt
return BigInt(a.i + b.i)
def Sub(a, b):
# type: (BigInt, BigInt) -> BigInt
return BigInt(a.i - b.i)
def Mul(a, b):
# type: (BigInt, BigInt) -> BigInt
return BigInt(a.i * b.i)
def Div(a, b):
# type: (BigInt, BigInt) -> BigInt
"""
Divide, for positive integers only
Question: does Oils behave like C remainder when it's positive? Then we
could be more efficient with a different layering?
"""
assert a.i >= 0 and b.i >= 0, (a.i, b.i)
return BigInt(a.i // b.i)
def Rem(a, b):
# type: (BigInt, BigInt) -> BigInt
"""
Remainder, for positive integers only
"""
assert a.i >= 0 and b.i >= 0, (a.i, b.i)
return BigInt(a.i % b.i)
def Equal(a, b):
# type: (BigInt, BigInt) -> bool
return a.i == b.i
def Greater(a, b):
# type: (BigInt, BigInt) -> bool
return a.i > b.i
# GreaterEq, Less, LessEq can all be expressed as the 2 ops above
def LShift(a, b):
# type: (BigInt, BigInt) -> BigInt
"""
Any semantic issues here? Signed left shift
"""
return BigInt(a.i << b.i)
def RShift(a, b):
# type: (BigInt, BigInt) -> BigInt
return BigInt(a.i >> b.i)
def BitAnd(a, b):
# type: (BigInt, BigInt) -> BigInt
return BigInt(a.i & b.i)
def BitOr(a, b):
# type: (BigInt, BigInt) -> BigInt
return BigInt(a.i | b.i)
def BitXor(a, b):
# type: (BigInt, BigInt) -> BigInt
return BigInt(a.i ^ b.i)
def BitNot(a):
# type: (BigInt) -> BigInt
return BigInt(~a.i)