github.com/MontFerret/ferret@v0.18.0/pkg/runtime/values/float.go (about)

     1  package values
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"hash/fnv"
     7  	"math"
     8  	"strconv"
     9  
    10  	"github.com/wI2L/jettison"
    11  
    12  	"github.com/MontFerret/ferret/pkg/runtime/core"
    13  	"github.com/MontFerret/ferret/pkg/runtime/values/types"
    14  )
    15  
    16  type Float float64
    17  
    18  var NaN = Float(math.NaN())
    19  
    20  const ZeroFloat = Float(0.0)
    21  
    22  func NewFloat(input float64) Float {
    23  	return Float(input)
    24  }
    25  
    26  func ParseFloat(input interface{}) (Float, error) {
    27  	if core.IsNil(input) {
    28  		return ZeroFloat, nil
    29  	}
    30  
    31  	i, ok := input.(float64)
    32  
    33  	if ok {
    34  		if i == 0 {
    35  			return ZeroFloat, nil
    36  		}
    37  
    38  		return Float(i), nil
    39  	}
    40  
    41  	// try to cast
    42  	str, ok := input.(string)
    43  
    44  	if ok {
    45  		i, err := strconv.Atoi(str)
    46  
    47  		if err == nil {
    48  			if i == 0 {
    49  				return ZeroFloat, nil
    50  			}
    51  
    52  			return Float(i), nil
    53  		}
    54  	}
    55  
    56  	return ZeroFloat, core.Error(core.ErrInvalidType, "expected 'float'")
    57  }
    58  
    59  func MustParseFloat(input interface{}) Float {
    60  	res, err := ParseFloat(input)
    61  
    62  	if err != nil {
    63  		panic(err)
    64  	}
    65  
    66  	return res
    67  }
    68  
    69  func IsNaN(input Float) Boolean {
    70  	return NewBoolean(math.IsNaN(float64(input)))
    71  }
    72  
    73  func IsInf(input Float, sign Int) Boolean {
    74  	return NewBoolean(math.IsInf(float64(input), int(sign)))
    75  }
    76  
    77  func (t Float) MarshalJSON() ([]byte, error) {
    78  	return jettison.MarshalOpts(float64(t), jettison.NoHTMLEscaping())
    79  }
    80  
    81  func (t Float) Type() core.Type {
    82  	return types.Float
    83  }
    84  
    85  func (t Float) String() string {
    86  	return fmt.Sprintf("%v", float64(t))
    87  }
    88  
    89  func (t Float) Compare(other core.Value) int64 {
    90  	otherType := other.Type()
    91  	raw := float64(t)
    92  
    93  	if otherType == types.Float {
    94  		f := other.Unwrap().(float64)
    95  
    96  		if raw == f {
    97  			return 0
    98  		}
    99  
   100  		if raw < f {
   101  			return -1
   102  		}
   103  
   104  		return +1
   105  	}
   106  
   107  	if otherType == types.Int {
   108  		i := other.Unwrap().(int)
   109  		f := float64(i)
   110  
   111  		if raw == f {
   112  			return 0
   113  		}
   114  
   115  		if raw < f {
   116  			return -1
   117  		}
   118  
   119  		return +1
   120  	}
   121  
   122  	return types.Compare(types.Float, otherType)
   123  }
   124  
   125  func (t Float) Unwrap() interface{} {
   126  	return float64(t)
   127  }
   128  
   129  func (t Float) Hash() uint64 {
   130  	h := fnv.New64a()
   131  
   132  	h.Write([]byte(t.Type().String()))
   133  	h.Write([]byte(":"))
   134  
   135  	bytes := make([]byte, 8)
   136  	binary.LittleEndian.PutUint64(bytes, math.Float64bits(float64(t)))
   137  	h.Write(bytes)
   138  
   139  	return h.Sum64()
   140  }
   141  
   142  func (t Float) Copy() core.Value {
   143  	return t
   144  }