summaryrefslogtreecommitdiff
path: root/js/src/Ice/Long.js
blob: cf748c8c4baf912b6fa54b555fc56374bedf1938 (plain)
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
// **********************************************************************
//
// Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved.
//
// This copy of Ice is licensed to you under the terms described in the
// ICE_LICENSE file included in this distribution.
//
// **********************************************************************

const Ice = require("../Ice/ModuleRegistry").Ice;

//
// The Long type represents a signed 64-bit integer as two 32-bit values
// corresponding to the high and low words.
//
class Long
{
    //
    // If only one argument is provide we assume it is a JavaScript Number,
    // and we convert it to two 32 bit words to fit in the Ice.Long internal
    // representation.
    //
    // If two arguments are provided we asume these are the high and low words
    // respectively.
    // 
    constructor(high = 0, low)
    {
        if(!Number.isSafeInteger(high))
        {
            throw new RangeError(low === undefined ?
                    "Number must be a safe integer" :
                    "High word must be a safe integer");
        }

        if(low === undefined)
        {
            this.low = high % Long.HIGH_MASK;
            this.high = Math.floor(high / Long.HIGH_MASK);
        }
        else
        {
            if(!Number.isSafeInteger(low))
            {
                throw new RangeError("Low word must be a safe integer");
            }
            if(low < 0 || low > Long.MAX_UINT32)
            {
                throw new RangeError("Low word must be between 0 and 0xFFFFFFFF");
            }
            if(high < 0 || high > Long.MAX_UINT32)
            {
                throw new RangeError("High word must be between 0 and 0xFFFFFFFF");
            }
            
            this.high = high;
            this.low = low;
        }
    }
    
    hashCode()
    {
        return this.low;
    }

    equals(rhs)
    {
        if(this === rhs)
        {
            return true;
        }
        if(!(rhs instanceof Long))
        {
            return false;
        }
        return this.high === rhs.high && this.low === rhs.low;
    }

    toString()
    {
        return this.high + ":" + this.low;
    }

    toNumber()
    {
        if((this.high & Long.SIGN_MASK) !== 0)
        {
            const l = (~this.low) >>> 0;
            const h = (~this.high) >>> 0;
            if(h > Long.HIGH_MAX || h == Long.HIGH_MAX && l == Long.MAX_UINT32)
            {
                return Number.NEGATIVE_INFINITY;
            }
            return -((h * Long.HIGH_MASK) + l + 1)
        }
        else
        {
            if(this.high > Long.HIGH_MAX)
            {
                return Number.POSITIVE_INFINITY;
            }
            return (this.high * Long.HIGH_MASK) + this.low;
        }
    }
}

//
// 2^32
// 
Long.MAX_UINT32 = 0xFFFFFFFF;

//
// (high & SIGN_MASK) != 0 denotes a negative number;
// that is, the most significant bit is set.
//
Long.SIGN_MASK = 0x80000000;

//
// When converting to a JavaScript Number we left shift the
// high word by 32 bits. As that isn't possible using JavaScript's
// left shift operator, we multiply the value by 2^32 which will
// produce the same result.
//
Long.HIGH_MASK = 0x100000000;

//
// The maximum value for the high word when coverting to
// a JavaScript Number is 2^21 - 1, in which case all
// 53 bits are used.
//
Long.HIGH_MAX = 0x1FFFFF;

Ice.Long = Long;
module.exports.Ice = Ice;