blob: a91ec53baa47f6c234e083ee29b649370181d7fd [file] [log] [blame]
// Copyright 2016 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package vdlconv
import (
"fmt"
)
// TODO(bprosnitz) The go compiler probably won't inline these functions because of the
// Errorf() call. Consider other variants, such as having the functions just return a
// boolean for overflow and output the error in the body of the generated function.
const (
// IEEE 754 represents float64 using 52 bits to represent the mantissa, with
// an extra implied leading bit. That gives us 53 bits to store integers
// without overflow - i.e. [0, (2^53)-1]. And since 2^53 is a small power of
// two, it can also be stored without loss via mantissa=1 exponent=53. Thus
// we have our max and min values. Ditto for float32, which uses 23 bits with
// an extra implied leading bit.
float64MaxInt = (1 << 53)
float64MinInt = -(1 << 53)
float32MaxInt = (1 << 24)
float32MinInt = -(1 << 24)
)
const (
shiftFor8Bit = 64 - 8
shiftFor16Bit = 64 - 16
shiftFor32Bit = 64 - 32
)
func Uint64ToUint8(x uint64) (uint8, error) {
if x != (x<<shiftFor8Bit)>>shiftFor8Bit {
return 0, fmt.Errorf("uint64 value %d cannot be converted to uint8 without loss", x)
}
return uint8(x), nil
}
func Uint64ToUint16(x uint64) (uint16, error) {
if x != (x<<shiftFor16Bit)>>shiftFor16Bit {
return 0, fmt.Errorf("uint64 value %d cannot be converted to uint16 without loss", x)
}
return uint16(x), nil
}
func Uint64ToUint32(x uint64) (uint32, error) {
if x != (x<<shiftFor32Bit)>>shiftFor32Bit {
return 0, fmt.Errorf("uint64 value %d cannot be converted to uint32 without loss", x)
}
return uint32(x), nil
}
func Uint64ToInt8(x uint64) (int8, error) {
ix := int64(x)
if ix < 0 || ix != (ix<<shiftFor8Bit)>>shiftFor8Bit {
return 0, fmt.Errorf("uint64 value %d cannot be converted to int8 without loss", x)
}
return int8(ix), nil
}
func Uint64ToInt16(x uint64) (int16, error) {
ix := int64(x)
if ix < 0 || ix != (ix<<shiftFor16Bit)>>shiftFor16Bit {
return 0, fmt.Errorf("uint64 value %d cannot be converted to int16 without loss", x)
}
return int16(ix), nil
}
func Uint64ToInt32(x uint64) (int32, error) {
ix := int64(x)
if ix < 0 || ix != (ix<<shiftFor32Bit)>>shiftFor32Bit {
return 0, fmt.Errorf("uint64 value %d cannot be converted to int32 without loss", x)
}
return int32(ix), nil
}
func Uint64ToInt64(x uint64) (int64, error) {
ix := int64(x)
if ix < 0 {
return 0, fmt.Errorf("uint64 value %d cannot be converted to int64 without loss", x)
}
return ix, nil
}
func Uint64ToFloat32(x uint64) (float32, error) {
if x > float32MaxInt {
return 0, fmt.Errorf("uint64 value %d cannot be converted to float32 without loss", x)
}
return float32(x), nil
}
func Uint64ToFloat64(x uint64) (float64, error) {
if x > float64MaxInt {
return 0, fmt.Errorf("uint64 value %d cannot be converted to float64 without loss", x)
}
return float64(x), nil
}
func Int64ToUint8(x int64) (uint8, error) {
ux := uint64(x)
if x < 0 || ux != (ux<<shiftFor8Bit)>>shiftFor8Bit {
return 0, fmt.Errorf("int64 value %d cannot be converted to uint8 without loss", x)
}
return uint8(ux), nil
}
func Int64ToUint16(x int64) (uint16, error) {
ux := uint64(x)
if x < 0 || ux != (ux<<shiftFor16Bit)>>shiftFor16Bit {
return 0, fmt.Errorf("int64 value %d cannot be converted to uint16 without loss", x)
}
return uint16(ux), nil
}
func Int64ToUint32(x int64) (uint32, error) {
ux := uint64(x)
if x < 0 || ux != (ux<<shiftFor32Bit)>>shiftFor32Bit {
return 0, fmt.Errorf("int64 value %d cannot be converted to uint32 without loss", x)
}
return uint32(ux), nil
}
func Int64ToUint64(x int64) (uint64, error) {
ux := uint64(x)
if x < 0 {
return 0, fmt.Errorf("int64 value %d cannot be converted to uint64 without loss", x)
}
return ux, nil
}
func Int64ToInt8(x int64) (int8, error) {
if x != (x<<shiftFor8Bit)>>shiftFor8Bit {
return 0, fmt.Errorf("int64 value %d cannot be converted to int8 without loss", x)
}
return int8(x), nil
}
func Int64ToInt16(x int64) (int16, error) {
if x != (x<<shiftFor16Bit)>>shiftFor16Bit {
return 0, fmt.Errorf("int64 value %d cannot be converted to int16 without loss", x)
}
return int16(x), nil
}
func Int64ToInt32(x int64) (int32, error) {
if x != (x<<shiftFor32Bit)>>shiftFor32Bit {
return 0, fmt.Errorf("int64 value %d cannot be converted to int32 without loss", x)
}
return int32(x), nil
}
func Int64ToFloat32(x int64) (float32, error) {
if x < float32MinInt || x > float32MaxInt {
return 0, fmt.Errorf("int64 value %d cannot be converted to float32 without loss", x)
}
return float32(x), nil
}
func Int64ToFloat64(x int64) (float64, error) {
if x < float64MinInt || x > float64MaxInt {
return 0, fmt.Errorf("int64 value %d cannot be converted to float64 without loss", x)
}
return float64(x), nil
}
func Float64ToUint8(x float64) (uint8, error) {
ux := uint64(x)
if x != float64(ux) || ux != (ux<<shiftFor8Bit)>>shiftFor8Bit {
return 0, fmt.Errorf("float64 value %f cannot be converted to uint8 without loss", x)
}
return uint8(ux), nil
}
func Float64ToUint16(x float64) (uint16, error) {
ux := uint64(x)
if x != float64(ux) || ux != (ux<<shiftFor16Bit)>>shiftFor16Bit {
return 0, fmt.Errorf("float64 value %f cannot be converted to uint16 without loss", x)
}
return uint16(ux), nil
}
func Float64ToUint32(x float64) (uint32, error) {
ux := uint64(x)
if x != float64(ux) || ux != (ux<<shiftFor32Bit)>>shiftFor32Bit {
return 0, fmt.Errorf("float64 value %f cannot be converted to uint32 without loss", x)
}
return uint32(ux), nil
}
func Float64ToUint64(x float64) (uint64, error) {
ux := uint64(x)
if x != float64(ux) {
return 0, fmt.Errorf("float64 value %f cannot be converted to uint64 without loss", x)
}
return ux, nil
}
func Float64ToInt8(x float64) (int8, error) {
ix := int64(x)
if x != float64(ix) || ix != (ix<<shiftFor8Bit)>>shiftFor8Bit {
return 0, fmt.Errorf("float64 value %f cannot be converted to int8 without loss", x)
}
return int8(ix), nil
}
func Float64ToInt16(x float64) (int16, error) {
ix := int64(x)
if x != float64(ix) || ix != (ix<<shiftFor16Bit)>>shiftFor16Bit {
return 0, fmt.Errorf("float64 value %f cannot be converted to int16 without loss", x)
}
return int16(ix), nil
}
func Float64ToInt32(x float64) (int32, error) {
ix := int64(x)
if x != float64(ix) || ix != (ix<<shiftFor32Bit)>>shiftFor32Bit {
return 0, fmt.Errorf("float64 value %f cannot be converted to int32 without loss", x)
}
return int32(ix), nil
}
func Float64ToInt64(x float64) (int64, error) {
ix := int64(x)
if x != float64(ix) {
return 0, fmt.Errorf("float64 value %f cannot be converted to int64 without loss", x)
}
return ix, nil
}
func Float64ToFloat32(x float64) (float32, error) {
return float32(x), nil
}