Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
grumpy
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
grumpy
Commits
bda6df5b
Commit
bda6df5b
authored
Feb 22, 2017
by
Dong-hee Na
Committed by
Dylan Trotter
Feb 22, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implemented float.__hash__(). (#261)
parent
004b7a84
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
79 additions
and
5 deletions
+79
-5
runtime/float.go
runtime/float.go
+55
-1
runtime/float_test.go
runtime/float_test.go
+22
-2
runtime/set_test.go
runtime/set_test.go
+2
-2
No files found.
runtime/float.go
View file @
bda6df5b
...
...
@@ -20,6 +20,8 @@ import (
"math/big"
"reflect"
"strconv"
"sync/atomic"
"unsafe"
)
// FloatType is the object representing the Python 'float' type.
...
...
@@ -29,11 +31,12 @@ var FloatType = newBasisType("float", reflect.TypeOf(Float{}), toFloatUnsafe, Ob
type
Float
struct
{
Object
value
float64
hash
int
}
// NewFloat returns a new Float holding the given floating point value.
func
NewFloat
(
value
float64
)
*
Float
{
return
&
Float
{
Object
{
typ
:
FloatType
},
value
}
return
&
Float
{
Object
:
Object
{
typ
:
FloatType
},
value
:
value
}
}
func
toFloatUnsafe
(
o
*
Object
)
*
Float
{
...
...
@@ -91,6 +94,22 @@ func floatGT(f *Frame, v, w *Object) (*Object, *BaseException) {
return
floatCompare
(
toFloatUnsafe
(
v
),
w
,
False
,
False
,
True
),
nil
}
func
floatHash
(
f
*
Frame
,
o
*
Object
)
(
*
Object
,
*
BaseException
)
{
v
:=
toFloatUnsafe
(
o
)
p
:=
(
*
unsafe
.
Pointer
)(
unsafe
.
Pointer
(
&
v
.
hash
))
if
lp
:=
atomic
.
LoadPointer
(
p
);
lp
!=
unsafe
.
Pointer
(
nil
)
{
return
(
*
Int
)(
lp
)
.
ToObject
(),
nil
}
hash
:=
hashFloat
(
v
.
Value
())
if
hash
==
-
1
{
hash
--
}
h
:=
NewInt
(
hash
)
atomic
.
StorePointer
(
p
,
unsafe
.
Pointer
(
h
))
return
h
.
ToObject
(),
nil
}
func
floatInt
(
f
*
Frame
,
o
*
Object
)
(
*
Object
,
*
BaseException
)
{
val
:=
toFloatUnsafe
(
o
)
.
Value
()
if
math
.
IsInf
(
val
,
0
)
{
...
...
@@ -250,6 +269,7 @@ func initFloatType(dict map[string]*Object) {
FloatType
.
slots
.
Float
=
&
unaryOpSlot
{
floatFloat
}
FloatType
.
slots
.
GE
=
&
binaryOpSlot
{
floatGE
}
FloatType
.
slots
.
GT
=
&
binaryOpSlot
{
floatGT
}
FloatType
.
slots
.
Hash
=
&
unaryOpSlot
{
floatHash
}
FloatType
.
slots
.
Int
=
&
unaryOpSlot
{
floatInt
}
FloatType
.
slots
.
Long
=
&
unaryOpSlot
{
floatLong
}
FloatType
.
slots
.
LE
=
&
binaryOpSlot
{
floatLE
}
...
...
@@ -355,6 +375,40 @@ func floatDivModOp(f *Frame, method string, v, w *Object, fun func(v, w float64)
return
NewFloat
(
x
)
.
ToObject
(),
nil
}
func
hashFloat
(
v
float64
)
int
{
if
math
.
IsNaN
(
v
)
{
return
0
}
if
math
.
IsInf
(
v
,
0
)
{
if
math
.
IsInf
(
v
,
1
)
{
return
314159
}
if
math
.
IsInf
(
v
,
-
1
)
{
return
-
271828
}
return
0
}
_
,
fracPart
:=
math
.
Modf
(
v
)
if
fracPart
==
0.0
{
i
:=
big
.
Int
{}
big
.
NewFloat
(
v
)
.
Int
(
&
i
)
if
numInIntRange
(
&
i
)
{
return
int
(
i
.
Int64
())
}
// TODO: hashBigInt() is not yet matched that of cpython or pypy.
return
hashBigInt
(
&
i
)
}
v
,
expo
:=
math
.
Frexp
(
v
)
v
*=
2147483648.0
hiPart
:=
int
(
v
)
v
=
(
v
-
float64
(
hiPart
))
*
2147483648.0
x
:=
int
(
hiPart
+
int
(
v
)
+
(
expo
<<
15
))
return
x
}
func
floatModFunc
(
v
,
w
float64
)
(
float64
,
bool
)
{
if
w
==
0.0
{
return
0
,
false
...
...
runtime/float_test.go
View file @
bda6df5b
...
...
@@ -151,6 +151,22 @@ func TestFloatLong(t *testing.T) {
}
}
func
TestFloatHash
(
t
*
testing
.
T
)
{
cases
:=
[]
invokeTestCase
{
{
args
:
wrapArgs
(
NewFloat
(
0.0
)),
want
:
NewInt
(
0
)
.
ToObject
()},
{
args
:
wrapArgs
(
NewFloat
(
3.14
)),
want
:
NewInt
(
3146129223
)
.
ToObject
()},
{
args
:
wrapArgs
(
NewFloat
(
42.0
)),
want
:
NewInt
(
42
)
.
ToObject
()},
{
args
:
wrapArgs
(
NewFloat
(
42.125
)),
want
:
NewInt
(
1413677056
)
.
ToObject
()},
{
args
:
wrapArgs
(
NewFloat
(
math
.
Inf
(
1
))),
want
:
NewInt
(
314159
)
.
ToObject
()},
{
args
:
wrapArgs
(
NewFloat
(
math
.
Inf
(
-
1
))),
want
:
NewInt
(
-
271828
)
.
ToObject
()},
{
args
:
wrapArgs
(
NewFloat
(
math
.
NaN
())),
want
:
NewInt
(
0
)
.
ToObject
()},
}
for
_
,
cas
:=
range
cases
{
if
err
:=
runInvokeTestCase
(
wrapFuncForTest
(
floatHash
),
&
cas
);
err
!=
""
{
t
.
Error
(
err
)
}
}
}
func
TestFloatIsTrue
(
t
*
testing
.
T
)
{
cases
:=
[]
invokeTestCase
{
{
args
:
wrapArgs
(
0.0
),
want
:
False
.
ToObject
()},
...
...
@@ -167,6 +183,10 @@ func TestFloatIsTrue(t *testing.T) {
func
TestFloatNew
(
t
*
testing
.
T
)
{
floatNew
:=
mustNotRaise
(
GetAttr
(
NewRootFrame
(),
FloatType
.
ToObject
(),
NewStr
(
"__new__"
),
nil
))
strictEqType
:=
newTestClassStrictEq
(
"StrictEq"
,
FloatType
)
newStrictEq
:=
func
(
v
float64
)
*
Object
{
f
:=
Float
{
Object
:
Object
{
typ
:
strictEqType
},
value
:
v
}
return
f
.
ToObject
()
}
subType
:=
newTestClass
(
"SubType"
,
[]
*
Type
{
FloatType
},
newStringDict
(
map
[
string
]
*
Object
{}))
subTypeObject
:=
(
&
Float
{
Object
:
Object
{
typ
:
subType
},
value
:
3.14
})
.
ToObject
()
goodSlotType
:=
newTestClass
(
"GoodSlot"
,
[]
*
Type
{
ObjectType
},
newStringDict
(
map
[
string
]
*
Object
{
...
...
@@ -203,8 +223,8 @@ func TestFloatNew(t *testing.T) {
{
args
:
wrapArgs
(
FloatType
,
newObject
(
goodSlotType
)),
want
:
NewFloat
(
3.14
)
.
ToObject
()},
{
args
:
wrapArgs
(
FloatType
,
newObject
(
badSlotType
)),
wantExc
:
mustCreateException
(
TypeErrorType
,
"__float__ returned non-float (type object)"
)},
{
args
:
wrapArgs
(
FloatType
,
newObject
(
slotSubTypeType
)),
want
:
subTypeObject
},
{
args
:
wrapArgs
(
strictEqType
,
3.14
),
want
:
(
&
Float
{
Object
{
typ
:
strictEqType
},
3.14
})
.
ToObject
(
)},
{
args
:
wrapArgs
(
strictEqType
,
newObject
(
goodSlotType
)),
want
:
(
&
Float
{
Object
{
typ
:
strictEqType
},
3.14
})
.
ToObject
(
)},
{
args
:
wrapArgs
(
strictEqType
,
3.14
),
want
:
newStrictEq
(
3.14
)},
{
args
:
wrapArgs
(
strictEqType
,
newObject
(
goodSlotType
)),
want
:
newStrictEq
(
3.14
)},
{
args
:
wrapArgs
(
strictEqType
,
newObject
(
badSlotType
)),
wantExc
:
mustCreateException
(
TypeErrorType
,
"__float__ returned non-float (type object)"
)},
{
args
:
wrapArgs
(),
wantExc
:
mustCreateException
(
TypeErrorType
,
"'__new__' requires 1 arguments"
)},
{
args
:
wrapArgs
(
IntType
),
wantExc
:
mustCreateException
(
TypeErrorType
,
"float.__new__(int): int is not a subtype of float"
)},
...
...
runtime/set_test.go
View file @
bda6df5b
...
...
@@ -184,10 +184,10 @@ func TestSetIter(t *testing.T) {
cases
:=
[]
invokeTestCase
{
{
args
:
wrapArgs
(
NewSet
()),
want
:
NewTuple
()
.
ToObject
()},
{
args
:
wrapArgs
(
newTestSet
(
1
,
2
,
3
)),
want
:
newTestTuple
(
1
,
2
,
3
)
.
ToObject
()},
{
args
:
wrapArgs
(
newTestSet
(
"foo"
,
3.14
)),
want
:
newTestTuple
(
3.14
,
"foo"
)
.
ToObject
()},
{
args
:
wrapArgs
(
newTestSet
(
"foo"
,
3.14
)),
want
:
newTestTuple
(
"foo"
,
3.14
)
.
ToObject
()},
{
args
:
wrapArgs
(
newTestFrozenSet
()),
want
:
NewTuple
()
.
ToObject
()},
{
args
:
wrapArgs
(
newTestFrozenSet
(
1
,
2
,
3
)),
want
:
newTestTuple
(
1
,
2
,
3
)
.
ToObject
()},
{
args
:
wrapArgs
(
newTestFrozenSet
(
"foo"
,
3.14
)),
want
:
newTestTuple
(
3.14
,
"foo"
)
.
ToObject
()},
{
args
:
wrapArgs
(
newTestFrozenSet
(
"foo"
,
3.14
)),
want
:
newTestTuple
(
"foo"
,
3.14
)
.
ToObject
()},
}
for
_
,
cas
:=
range
cases
{
if
err
:=
runInvokeTestCase
(
fun
,
&
cas
);
err
!=
""
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment