Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
THRIFT-3022 Compact protocol for Haxe
Client: Haxe
Patch: Jens Geyer

This closes #388
  • Loading branch information
Jens-G committed Mar 5, 2015
1 parent 6f7399b commit 426ab86
Show file tree
Hide file tree
Showing 9 changed files with 1,162 additions and 73 deletions.
159 changes: 159 additions & 0 deletions lib/haxe/src/org/apache/thrift/helper/BitConverter.hx
@@ -0,0 +1,159 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.thrift.helper;

import haxe.Int64;
import haxe.io.Bytes;
import haxe.io.BytesBuffer;

class BitConverter {

public static function DoubleToInt64Bits( db : Float) : Int64 {
var buf = new BytesBuffer();
buf.addDouble( db);
return bytesToLong( buf.getBytes());
}


public static function Int64BitsToDouble( i64 : Int64) : Float {
var buf = new BytesBuffer();
buf.add( fixedLongToBytes( i64));
return buf.getBytes().getDouble(0);
}



/**
* Convert a long into little-endian bytes in buf starting at off and going
* until off+7.
*/
public static function fixedLongToBytes( n : Int64) : Bytes {
var buf = Bytes.alloc(8);
buf.set( 0, Int64.getLow( Int64.and( n, Int64.make(0, 0xff))));
buf.set( 1, Int64.getLow( Int64.and( Int64.shr( n, 8), Int64.make(0, 0xff))));
buf.set( 2, Int64.getLow( Int64.and( Int64.shr( n, 16), Int64.make(0, 0xff))));
buf.set( 3, Int64.getLow( Int64.and( Int64.shr( n, 24), Int64.make(0, 0xff))));
buf.set( 4, Int64.getLow( Int64.and( Int64.shr( n, 32), Int64.make(0, 0xff))));
buf.set( 5, Int64.getLow( Int64.and( Int64.shr( n, 40), Int64.make(0, 0xff))));
buf.set( 6, Int64.getLow( Int64.and( Int64.shr( n, 48), Int64.make(0, 0xff))));
buf.set( 7, Int64.getLow( Int64.and( Int64.shr( n, 56), Int64.make(0, 0xff))));
return buf;
}

/**
* Note that it's important that the mask bytes are long literals,
* otherwise they'll default to ints, and when you shift an int left 56 bits,
* you just get a messed up int.
*/
public static function bytesToLong( bytes : Bytes) : Int64 {
var result : Int64 = Int64.make(0, 0);
result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(7)));
result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(6)));
result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(5)));
result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(4)));
result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(3)));
result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(2)));
result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(1)));
result = Int64.or( Int64.shl( result, 8), Int64.make( 0, bytes.get(0)));
return result;
}


#if debug
private static function TestBTL( test : Int64) : Void {
var buf : Bytes = fixedLongToBytes( test);
var erg = bytesToLong(buf);
if ( Int64.compare( erg, test) != 0)
throw 'BitConverter.bytesToLongTest($test) failed: $erg';
}
#end


#if debug
private static function TestPair( a : Float, b : Int64) : Void {
var bx = DoubleToInt64Bits(a);
if ( Int64.compare( bx, b) != 0)
throw 'BitConverter.TestPair: DoubleToInt64Bits($a): expected $b, got $bx';
var ax = Int64BitsToDouble(b);
if( ax != a)
throw 'BitConverter.TestPair: Int64BitsToDouble($b: expected $a, got $ax';
}
#end


#if debug
public static function UnitTest() : Void {

// bytesToLong()
var i : Int;
TestBTL( Int64.make(0,0));
for ( i in 0 ... 62) {
TestBTL( Int64.shl( Int64.make(0,1), i));
TestBTL( Int64.sub( Int64.make(0,0), Int64.shl( Int64.make(0,1), i)));
}
TestBTL( Int64.make(0x7FFFFFFF,0xFFFFFFFF));
TestBTL( Int64.make(cast(0x80000000,Int),0x00000000));

// DoubleToInt64Bits;
TestPair( 1.0000000000000000E+000, Int64.make(cast(0x3FF00000,Int),cast(0x00000000,Int)));
TestPair( 1.5000000000000000E+001, Int64.make(cast(0x402E0000,Int),cast(0x00000000,Int)));
TestPair( 2.5500000000000000E+002, Int64.make(cast(0x406FE000,Int),cast(0x00000000,Int)));
TestPair( 4.2949672950000000E+009, Int64.make(cast(0x41EFFFFF,Int),cast(0xFFE00000,Int)));
TestPair( 3.9062500000000000E-003, Int64.make(cast(0x3F700000,Int),cast(0x00000000,Int)));
TestPair( 2.3283064365386963E-010, Int64.make(cast(0x3DF00000,Int),cast(0x00000000,Int)));
TestPair( 1.2345678901230000E-300, Int64.make(cast(0x01AA74FE,Int),cast(0x1C1E7E45,Int)));
TestPair( 1.2345678901234500E-150, Int64.make(cast(0x20D02A36,Int),cast(0x586DB4BB,Int)));
TestPair( 1.2345678901234565E+000, Int64.make(cast(0x3FF3C0CA,Int),cast(0x428C59FA,Int)));
TestPair( 1.2345678901234567E+000, Int64.make(cast(0x3FF3C0CA,Int),cast(0x428C59FB,Int)));
TestPair( 1.2345678901234569E+000, Int64.make(cast(0x3FF3C0CA,Int),cast(0x428C59FC,Int)));
TestPair( 1.2345678901234569E+150, Int64.make(cast(0x5F182344,Int),cast(0xCD3CDF9F,Int)));
TestPair( 1.2345678901234569E+300, Int64.make(cast(0x7E3D7EE8,Int),cast(0xBCBBD352,Int)));
TestPair( -1.7976931348623157E+308, Int64.make(cast(0xFFEFFFFF,Int),cast(0xFFFFFFFF,Int)));
TestPair( 1.7976931348623157E+308, Int64.make(cast(0x7FEFFFFF,Int),cast(0xFFFFFFFF,Int)));
TestPair( 4.9406564584124654E-324, Int64.make(cast(0x00000000,Int),cast(0x00000001,Int)));
TestPair( 0.0000000000000000E+000, Int64.make(cast(0x00000000,Int),cast(0x00000000,Int)));
TestPair( 4.94065645841247E-324, Int64.make(cast(0x00000000,Int),cast(0x00000001,Int)));
TestPair( 3.2378592100206092E-319, Int64.make(cast(0x00000000,Int),cast(0x0000FFFF,Int)));
TestPair( 1.3906711615669959E-309, Int64.make(cast(0x0000FFFF,Int),cast(0xFFFFFFFF,Int)));
TestPair( Math.NEGATIVE_INFINITY, Int64.make(cast(0xFFF00000,Int),cast(0x00000000,Int)));
TestPair( Math.POSITIVE_INFINITY, Int64.make(cast(0x7FF00000,Int),cast(0x00000000,Int)));

// NaN is special
var i64nan = DoubleToInt64Bits( Math.NaN);
var i64cmp = Int64.make(cast(0xFFF80000, Int), cast(0x00000000, Int));
if ( ! Math.isNaN( Int64BitsToDouble( i64cmp)))
throw 'BitConverter NaN-Test #1: expected NaN';

// For doubles, a quiet NaN is a bit pattern
// between 7FF8000000000000 and 7FFFFFFFFFFFFFFF
// or FFF8000000000000 and FFFFFFFFFFFFFFFF
var min1 = Int64.make( cast(0x7FF80000, Int), cast(0x00000000, Int));
var max1 = Int64.make( cast(0x7FFFFFFF, Int), cast(0xFFFFFFFF, Int));
var min2 = Int64.make( cast(0xFFF80000, Int), cast(0x00000000, Int));
var max2 = Int64.make( cast(0xFFFFFFFF, Int), cast(0xFFFFFFFF, Int));
var ok1 = (Int64.compare( min1, i64nan) <= 0) && (Int64.compare( i64nan, max1) <= 0);
var ok2 = (Int64.compare( min2, i64nan) <= 0) && (Int64.compare( i64nan, max2) <= 0);
if( ! (ok1 || ok2))
throw 'BitConverter NaN-Test #2: failed';
}
#end

}

128 changes: 128 additions & 0 deletions lib/haxe/src/org/apache/thrift/helper/ZigZag.hx
@@ -0,0 +1,128 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.thrift.helper;

import haxe.Int64;

class ZigZag {

/**
* Convert n into a zigzag int. This allows negative numbers to be
* represented compactly as a varint.
*/
public static function FromInt( n : Int) : UInt {
return cast(n << 1,UInt) ^ cast(n >> 31,UInt);
}


/**
* Convert from zigzag int to int.
*/
public static function ToInt( n : UInt) : Int {
return (0x7FFFFFFF & cast(n >> 1,Int)) ^ (-cast(n & 1,Int));
}


/**
* Convert l into a zigzag long. This allows negative numbers to be
* represented compactly as a varint.
*/
public static function FromLong( n : Int64) : Int64 {
return Int64.xor( Int64.shl(n, 1), Int64.shr(n, 63));
}


/**
* Convert from zigzag long to long.
*/
public static function ToLong( n : Int64) : Int64 {
return Int64.xor(
Int64.and(
Int64.shr(n, 1),
Int64.make(0x7FFFFFFF, 0xFFFFFFFF)),
Int64.sub(
Int64.make(0, 0),
Int64.and(n, Int64.make(0,1))));
}


#if debug
private static function Test32( test : Int) : Void {
var a : UInt = ZigZag.FromInt( test);
var b : Int = ZigZag.ToInt(a);
if( test != b)
throw 'ZigZag.Test32($test) failed: a = $a, b = $b';
}
#end



#if debug
private static function Test64( test : haxe.Int64) : Void {
var a : Int64 = ZigZag.FromLong( test);
var b : Int64 = ZigZag.ToLong(a);
if( Int64.compare( test, b) != 0)
throw 'ZigZag.Test64($test) failed: a = $a, b = $b';
}
#end


#if debug
public static function UnitTest() : Void {
var u1 : UInt = 0xFFFFFFFE;
var u2 : UInt = 0xFFFFFFFF;

// protobuf testcases
if( FromInt(0) != 0) throw 'pb #1 to ZigZag';
if( FromInt(-1) != 1) throw 'pb #2 to ZigZag';
if( FromInt(1) != 2) throw 'pb #3 to ZigZag';
if( FromInt(-2) != 3) throw 'pb #4 to ZigZag';
if( FromInt(2147483647) != u1) throw 'pb #5 to ZigZag';
if( FromInt(-2147483648) != u2) throw 'pb #6 to ZigZag';

// protobuf testcases
if( ToInt(0) != 0) throw 'pb #1 from ZigZag';
if( ToInt(1) != -1) throw 'pb #2 from ZigZag';
if( ToInt(2) != 1) throw 'pb #3 from ZigZag';
if( ToInt(3) != -2) throw 'pb #4 from ZigZag';
if( ToInt(u1) != 2147483647) throw 'pb #5 from ZigZag, got ${ToInt(u1)}';
if( ToInt(u2) != -2147483648) throw 'pb #6 from ZigZag, got ${ToInt(u2)}';

// back and forth 32
Test32( 0);
for( i in 0 ... 30) {
Test32( 1 << i);
Test32( -(1 << i));
}
Test32( 0x7FFFFFFF);
Test32( cast(0x80000000,Int));

// back and forth 64
Test64( Int64.make(0,0));
for( i in 0 ... 62) {
Test64( Int64.shl( Int64.make(0,1), i));
Test64( Int64.sub( Int64.make(0,0), Int64.shl( Int64.make(0,1), i)));
}
Test64( Int64.make(0x7FFFFFFF,0xFFFFFFFF));
Test64( Int64.make(cast(0x80000000,Int),0x00000000));
}
#end
}

0 comments on commit 426ab86

Please sign in to comment.