]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | /* |
2 | * Licensed to the Apache Software Foundation (ASF) under one | |
3 | * or more contributor license agreements. See the NOTICE file | |
4 | * distributed with this work for additional information | |
5 | * regarding copyright ownership. The ASF licenses this file | |
6 | * to you under the Apache License, Version 2.0 (the | |
7 | * "License"); you may not use this file except in compliance | |
8 | * with the License. You may obtain a copy of the License at | |
9 | * | |
10 | * http://www.apache.org/licenses/LICENSE-2.0 | |
11 | * | |
12 | * Unless required by applicable law or agreed to in writing, | |
13 | * software distributed under the License is distributed on an | |
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
15 | * KIND, either express or implied. See the License for the | |
16 | * specific language governing permissions and limitations | |
17 | * under the License. | |
18 | */ | |
19 | ||
20 | package org.apache.thrift.helper; | |
21 | ||
22 | import haxe.Int64; | |
23 | import haxe.io.Bytes; | |
24 | import haxe.io.BytesBuffer; | |
25 | ||
26 | class BitConverter { | |
27 | ||
28 | public static function DoubleToInt64Bits( db : Float) : Int64 { | |
29 | var buf = new BytesBuffer(); | |
30 | buf.addDouble( db); | |
31 | return bytesToLong( buf.getBytes()); | |
32 | } | |
33 | ||
34 | ||
35 | public static function Int64BitsToDouble( i64 : Int64) : Float { | |
36 | var buf = new BytesBuffer(); | |
37 | buf.add( fixedLongToBytes( i64)); | |
38 | return buf.getBytes().getDouble(0); | |
39 | } | |
40 | ||
41 | ||
42 | ||
43 | /** | |
44 | * Convert a long into little-endian bytes in buf starting at off and going | |
45 | * until off+7. | |
46 | */ | |
47 | public static function fixedLongToBytes( n : Int64) : Bytes { | |
48 | var buf = Bytes.alloc(8); | |
49 | #if( haxe_ver < 3.2) | |
50 | buf.set( 0, Int64.getLow( Int64.and( n, Int64.make(0, 0xff)))); | |
51 | buf.set( 1, Int64.getLow( Int64.and( Int64.shr( n, 8), Int64.make(0, 0xff)))); | |
52 | buf.set( 2, Int64.getLow( Int64.and( Int64.shr( n, 16), Int64.make(0, 0xff)))); | |
53 | buf.set( 3, Int64.getLow( Int64.and( Int64.shr( n, 24), Int64.make(0, 0xff)))); | |
54 | buf.set( 4, Int64.getLow( Int64.and( Int64.shr( n, 32), Int64.make(0, 0xff)))); | |
55 | buf.set( 5, Int64.getLow( Int64.and( Int64.shr( n, 40), Int64.make(0, 0xff)))); | |
56 | buf.set( 6, Int64.getLow( Int64.and( Int64.shr( n, 48), Int64.make(0, 0xff)))); | |
57 | buf.set( 7, Int64.getLow( Int64.and( Int64.shr( n, 56), Int64.make(0, 0xff)))); | |
58 | #else | |
59 | buf.set( 0, Int64.and( n, Int64.make(0, 0xff)).low); | |
60 | buf.set( 1, Int64.and( Int64.shr( n, 8), Int64.make(0, 0xff)).low); | |
61 | buf.set( 2, Int64.and( Int64.shr( n, 16), Int64.make(0, 0xff)).low); | |
62 | buf.set( 3, Int64.and( Int64.shr( n, 24), Int64.make(0, 0xff)).low); | |
63 | buf.set( 4, Int64.and( Int64.shr( n, 32), Int64.make(0, 0xff)).low); | |
64 | buf.set( 5, Int64.and( Int64.shr( n, 40), Int64.make(0, 0xff)).low); | |
65 | buf.set( 6, Int64.and( Int64.shr( n, 48), Int64.make(0, 0xff)).low); | |
66 | buf.set( 7, Int64.and( Int64.shr( n, 56), Int64.make(0, 0xff)).low); | |
67 | #end | |
68 | return buf; | |
69 | } | |
70 | ||
71 | /** | |
72 | * Note that it's important that the mask bytes are long literals, | |
73 | * otherwise they'll default to ints, and when you shift an int left 56 bits, | |
74 | * you just get a messed up int. | |
75 | */ | |
76 | public static function bytesToLong( bytes : Bytes) : Int64 { | |
77 | var result : Int64 = Int64.make(0, 0); | |
78 | result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(7))); | |
79 | result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(6))); | |
80 | result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(5))); | |
81 | result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(4))); | |
82 | result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(3))); | |
83 | result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(2))); | |
84 | result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(1))); | |
85 | result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(0))); | |
86 | return result; | |
87 | } | |
88 | ||
89 | ||
90 | #if debug | |
91 | private static function TestBTL( test : Int64) : Void { | |
92 | var buf : Bytes = fixedLongToBytes( test); | |
93 | var erg = bytesToLong(buf); | |
94 | if ( Int64.compare( erg, test) != 0) | |
95 | throw 'BitConverter.bytesToLongTest($test) failed: $erg'; | |
96 | } | |
97 | #end | |
98 | ||
99 | ||
100 | #if debug | |
101 | private static function TestPair( a : Float, b : Int64) : Void { | |
102 | var bx = DoubleToInt64Bits(a); | |
103 | if ( Int64.compare( bx, b) != 0) | |
104 | throw 'BitConverter.TestPair: DoubleToInt64Bits($a): expected $b, got $bx'; | |
105 | var ax = Int64BitsToDouble(b); | |
106 | if( ax != a) | |
107 | throw 'BitConverter.TestPair: Int64BitsToDouble($b: expected $a, got $ax'; | |
108 | } | |
109 | #end | |
110 | ||
111 | ||
112 | #if debug | |
113 | public static function UnitTest() : Void { | |
114 | ||
115 | // bytesToLong() | |
116 | var i : Int; | |
117 | TestBTL( Int64.make(0,0)); | |
118 | for ( i in 0 ... 62) { | |
119 | TestBTL( Int64.shl( Int64.make(0,1), i)); | |
120 | TestBTL( Int64.sub( Int64.make(0,0), Int64.shl( Int64.make(0,1), i))); | |
121 | } | |
122 | TestBTL( Int64.make(0x7FFFFFFF,0xFFFFFFFF)); | |
123 | TestBTL( Int64.make(cast(0x80000000,Int),0x00000000)); | |
124 | ||
125 | // DoubleToInt64Bits; | |
126 | TestPair( 1.0000000000000000E+000, Int64.make(cast(0x3FF00000,Int),cast(0x00000000,Int))); | |
127 | TestPair( 1.5000000000000000E+001, Int64.make(cast(0x402E0000,Int),cast(0x00000000,Int))); | |
128 | TestPair( 2.5500000000000000E+002, Int64.make(cast(0x406FE000,Int),cast(0x00000000,Int))); | |
129 | TestPair( 4.2949672950000000E+009, Int64.make(cast(0x41EFFFFF,Int),cast(0xFFE00000,Int))); | |
130 | TestPair( 3.9062500000000000E-003, Int64.make(cast(0x3F700000,Int),cast(0x00000000,Int))); | |
131 | TestPair( 2.3283064365386963E-010, Int64.make(cast(0x3DF00000,Int),cast(0x00000000,Int))); | |
132 | TestPair( 1.2345678901230000E-300, Int64.make(cast(0x01AA74FE,Int),cast(0x1C1E7E45,Int))); | |
133 | TestPair( 1.2345678901234500E-150, Int64.make(cast(0x20D02A36,Int),cast(0x586DB4BB,Int))); | |
134 | TestPair( 1.2345678901234565E+000, Int64.make(cast(0x3FF3C0CA,Int),cast(0x428C59FA,Int))); | |
135 | TestPair( 1.2345678901234567E+000, Int64.make(cast(0x3FF3C0CA,Int),cast(0x428C59FB,Int))); | |
136 | TestPair( 1.2345678901234569E+000, Int64.make(cast(0x3FF3C0CA,Int),cast(0x428C59FC,Int))); | |
137 | TestPair( 1.2345678901234569E+150, Int64.make(cast(0x5F182344,Int),cast(0xCD3CDF9F,Int))); | |
138 | TestPair( 1.2345678901234569E+300, Int64.make(cast(0x7E3D7EE8,Int),cast(0xBCBBD352,Int))); | |
139 | TestPair( -1.7976931348623157E+308, Int64.make(cast(0xFFEFFFFF,Int),cast(0xFFFFFFFF,Int))); | |
140 | TestPair( 1.7976931348623157E+308, Int64.make(cast(0x7FEFFFFF,Int),cast(0xFFFFFFFF,Int))); | |
141 | TestPair( 4.9406564584124654E-324, Int64.make(cast(0x00000000,Int),cast(0x00000001,Int))); | |
142 | TestPair( 0.0000000000000000E+000, Int64.make(cast(0x00000000,Int),cast(0x00000000,Int))); | |
143 | TestPair( 4.94065645841247E-324, Int64.make(cast(0x00000000,Int),cast(0x00000001,Int))); | |
144 | TestPair( 3.2378592100206092E-319, Int64.make(cast(0x00000000,Int),cast(0x0000FFFF,Int))); | |
145 | TestPair( 1.3906711615669959E-309, Int64.make(cast(0x0000FFFF,Int),cast(0xFFFFFFFF,Int))); | |
146 | TestPair( Math.NEGATIVE_INFINITY, Int64.make(cast(0xFFF00000,Int),cast(0x00000000,Int))); | |
147 | TestPair( Math.POSITIVE_INFINITY, Int64.make(cast(0x7FF00000,Int),cast(0x00000000,Int))); | |
148 | ||
149 | // NaN is special | |
150 | var i64nan = DoubleToInt64Bits( Math.NaN); | |
151 | var i64cmp = Int64.make(cast(0xFFF80000, Int), cast(0x00000000, Int)); | |
152 | if ( ! Math.isNaN( Int64BitsToDouble( i64cmp))) | |
153 | throw 'BitConverter NaN-Test #1: expected NaN'; | |
154 | ||
155 | // For doubles, a quiet NaN is a bit pattern | |
156 | // between 7FF8000000000000 and 7FFFFFFFFFFFFFFF | |
157 | // or FFF8000000000000 and FFFFFFFFFFFFFFFF | |
158 | var min1 = Int64.make( cast(0x7FF80000, Int), cast(0x00000000, Int)); | |
159 | var max1 = Int64.make( cast(0x7FFFFFFF, Int), cast(0xFFFFFFFF, Int)); | |
160 | var min2 = Int64.make( cast(0xFFF80000, Int), cast(0x00000000, Int)); | |
161 | var max2 = Int64.make( cast(0xFFFFFFFF, Int), cast(0xFFFFFFFF, Int)); | |
162 | var ok1 = (Int64.compare( min1, i64nan) <= 0) && (Int64.compare( i64nan, max1) <= 0); | |
163 | var ok2 = (Int64.compare( min2, i64nan) <= 0) && (Int64.compare( i64nan, max2) <= 0); | |
164 | if( ! (ok1 || ok2)) | |
165 | throw 'BitConverter NaN-Test #2: failed'; | |
166 | } | |
167 | #end | |
168 | ||
169 | } | |
170 |