| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- package msgp
- import (
- "math"
- "math/bits"
- "strconv"
- )
- // The portable parts of the Number implementation
- // Number can be
- // an int64, uint64, float32,
- // or float64 internally.
- // It can decode itself
- // from any of the native
- // messagepack number types.
- // The zero-value of Number
- // is Int(0). Using the equality
- // operator with Number compares
- // both the type and the value
- // of the number.
- type Number struct {
- // internally, this
- // is just a tagged union.
- // the raw bits of the number
- // are stored the same way regardless.
- bits uint64
- typ Type
- }
- // AsInt sets the number to an int64.
- func (n *Number) AsInt(i int64) {
- // we always store int(0)
- // as {0, InvalidType} in
- // order to preserve
- // the behavior of the == operator
- if i == 0 {
- n.typ = InvalidType
- n.bits = 0
- return
- }
- n.typ = IntType
- n.bits = uint64(i)
- }
- // AsUint sets the number to a uint64.
- func (n *Number) AsUint(u uint64) {
- n.typ = UintType
- n.bits = u
- }
- // AsFloat32 sets the value of the number
- // to a float32.
- func (n *Number) AsFloat32(f float32) {
- n.typ = Float32Type
- n.bits = uint64(math.Float32bits(f))
- }
- // AsFloat64 sets the value of the
- // number to a float64.
- func (n *Number) AsFloat64(f float64) {
- n.typ = Float64Type
- n.bits = math.Float64bits(f)
- }
- // Int casts the number as an int64, and
- // returns whether or not that was the
- // underlying type.
- func (n *Number) Int() (int64, bool) {
- return int64(n.bits), n.typ == IntType || n.typ == InvalidType
- }
- // Uint casts the number as a uint64, and returns
- // whether or not that was the underlying type.
- func (n *Number) Uint() (uint64, bool) {
- return n.bits, n.typ == UintType
- }
- // Float casts the number to a float64, and
- // returns whether that was the underlying
- // type (either a float64 or a float32).
- func (n *Number) Float() (float64, bool) {
- switch n.typ {
- case Float32Type:
- return float64(math.Float32frombits(uint32(n.bits))), true
- case Float64Type:
- return math.Float64frombits(n.bits), true
- default:
- return 0.0, false
- }
- }
- // Type will return one of:
- // Float64Type, Float32Type, UintType, or IntType.
- func (n *Number) Type() Type {
- if n.typ == InvalidType {
- return IntType
- }
- return n.typ
- }
- // DecodeMsg implements msgp.Decodable
- func (n *Number) DecodeMsg(r *Reader) error {
- typ, err := r.NextType()
- if err != nil {
- return err
- }
- switch typ {
- case Float32Type:
- f, err := r.ReadFloat32()
- if err != nil {
- return err
- }
- n.AsFloat32(f)
- return nil
- case Float64Type:
- f, err := r.ReadFloat64()
- if err != nil {
- return err
- }
- n.AsFloat64(f)
- return nil
- case IntType:
- i, err := r.ReadInt64()
- if err != nil {
- return err
- }
- n.AsInt(i)
- return nil
- case UintType:
- u, err := r.ReadUint64()
- if err != nil {
- return err
- }
- n.AsUint(u)
- return nil
- default:
- return TypeError{Encoded: typ, Method: IntType}
- }
- }
- // UnmarshalMsg implements msgp.Unmarshaler
- func (n *Number) UnmarshalMsg(b []byte) ([]byte, error) {
- typ := NextType(b)
- switch typ {
- case IntType:
- i, o, err := ReadInt64Bytes(b)
- if err != nil {
- return b, err
- }
- n.AsInt(i)
- return o, nil
- case UintType:
- u, o, err := ReadUint64Bytes(b)
- if err != nil {
- return b, err
- }
- n.AsUint(u)
- return o, nil
- case Float64Type:
- f, o, err := ReadFloat64Bytes(b)
- if err != nil {
- return b, err
- }
- n.AsFloat64(f)
- return o, nil
- case Float32Type:
- f, o, err := ReadFloat32Bytes(b)
- if err != nil {
- return b, err
- }
- n.AsFloat32(f)
- return o, nil
- default:
- return b, TypeError{Method: IntType, Encoded: typ}
- }
- }
- // MarshalMsg implements msgp.Marshaler
- func (n *Number) MarshalMsg(b []byte) ([]byte, error) {
- switch n.typ {
- case IntType:
- return AppendInt64(b, int64(n.bits)), nil
- case UintType:
- return AppendUint64(b, n.bits), nil
- case Float64Type:
- return AppendFloat64(b, math.Float64frombits(n.bits)), nil
- case Float32Type:
- return AppendFloat32(b, math.Float32frombits(uint32(n.bits))), nil
- default:
- return AppendInt64(b, 0), nil
- }
- }
- // EncodeMsg implements msgp.Encodable
- func (n *Number) EncodeMsg(w *Writer) error {
- switch n.typ {
- case IntType:
- return w.WriteInt64(int64(n.bits))
- case UintType:
- return w.WriteUint64(n.bits)
- case Float64Type:
- return w.WriteFloat64(math.Float64frombits(n.bits))
- case Float32Type:
- return w.WriteFloat32(math.Float32frombits(uint32(n.bits)))
- default:
- return w.WriteInt64(0)
- }
- }
- // CoerceInt attempts to coerce the value of
- // the number into a signed integer and returns
- // whether it was successful.
- // "Success" implies that no precision in the value of
- // the number was lost, which means that the number was an integer or
- // a floating point that mapped exactly to an integer without rounding.
- func (n *Number) CoerceInt() (int64, bool) {
- switch n.typ {
- case InvalidType, IntType:
- // InvalidType just means un-initialized.
- return int64(n.bits), true
- case UintType:
- return int64(n.bits), n.bits <= math.MaxInt64
- case Float32Type:
- f := math.Float32frombits(uint32(n.bits))
- if n.isExactInt() && f <= math.MaxInt64 && f >= math.MinInt64 {
- return int64(f), true
- }
- if n.bits == 0 || n.bits == 1<<31 {
- return 0, true
- }
- case Float64Type:
- f := math.Float64frombits(n.bits)
- if n.isExactInt() && f <= math.MaxInt64 && f >= math.MinInt64 {
- return int64(f), true
- }
- return 0, n.bits == 0 || n.bits == 1<<63
- }
- return 0, false
- }
- // CoerceUInt attempts to coerce the value of
- // the number into an unsigned integer and returns
- // whether it was successful.
- // "Success" implies that no precision in the value of
- // the number was lost, which means that the number was an integer or
- // a floating point that mapped exactly to an integer without rounding.
- func (n *Number) CoerceUInt() (uint64, bool) {
- switch n.typ {
- case InvalidType, IntType:
- // InvalidType just means un-initialized.
- if int64(n.bits) >= 0 {
- return n.bits, true
- }
- case UintType:
- return n.bits, true
- case Float32Type:
- f := math.Float32frombits(uint32(n.bits))
- if f >= 0 && f <= math.MaxUint64 && n.isExactInt() {
- return uint64(f), true
- }
- if n.bits == 0 || n.bits == 1<<31 {
- return 0, true
- }
- case Float64Type:
- f := math.Float64frombits(n.bits)
- if f >= 0 && f <= math.MaxUint64 && n.isExactInt() {
- return uint64(f), true
- }
- return 0, n.bits == 0 || n.bits == 1<<63
- }
- return 0, false
- }
- // isExactInt will return true if the number represents an integer value.
- // NaN, Inf returns false.
- func (n *Number) isExactInt() bool {
- var eBits int // Exponent bits
- var mBits int // Mantissa bits
- switch n.typ {
- case InvalidType, IntType, UintType:
- return true
- case Float32Type:
- eBits = 8
- mBits = 23
- case Float64Type:
- eBits = 11
- mBits = 52
- default:
- return false
- }
- // Calculate float parts
- exp := int(n.bits>>mBits) & ((1 << eBits) - 1)
- mant := n.bits & ((1 << mBits) - 1)
- if exp == 0 && mant == 0 {
- // Handle zero value.
- return true
- }
- exp -= (1 << (eBits - 1)) - 1
- if exp < 0 || exp == 1<<(eBits-1) {
- // Negative exponent is never integer (except zero handled above)
- // Handles NaN (exp all 1s)
- return false
- }
- if exp >= mBits {
- // If we have more exponent than mantissa bits it is always an integer.
- return true
- }
- // Check if all bits below the exponent are zero.
- return bits.TrailingZeros64(mant) >= mBits-exp
- }
- // CoerceFloat returns the number as a float64.
- // If the number is an integer, it will be
- // converted to a float64 with the closest representation.
- func (n *Number) CoerceFloat() float64 {
- switch n.typ {
- case IntType:
- return float64(int64(n.bits))
- case UintType:
- return float64(n.bits)
- case Float32Type:
- return float64(math.Float32frombits(uint32(n.bits)))
- case Float64Type:
- return math.Float64frombits(n.bits)
- default:
- return 0.0
- }
- }
- // Msgsize implements msgp.Sizer
- func (n *Number) Msgsize() int {
- switch n.typ {
- case Float32Type:
- return Float32Size
- case Float64Type:
- return Float64Size
- case IntType:
- return Int64Size
- case UintType:
- return Uint64Size
- default:
- return 1 // fixint(0)
- }
- }
- // MarshalJSON implements json.Marshaler
- func (n *Number) MarshalJSON() ([]byte, error) {
- t := n.Type()
- if t == InvalidType {
- return []byte{'0'}, nil
- }
- out := make([]byte, 0, 32)
- switch t {
- case Float32Type, Float64Type:
- f, _ := n.Float()
- return strconv.AppendFloat(out, f, 'f', -1, 64), nil
- case IntType:
- i, _ := n.Int()
- return strconv.AppendInt(out, i, 10), nil
- case UintType:
- u, _ := n.Uint()
- return strconv.AppendUint(out, u, 10), nil
- default:
- panic("(*Number).typ is invalid")
- }
- }
- // String implements fmt.Stringer
- func (n *Number) String() string {
- switch n.typ {
- case InvalidType:
- return "0"
- case Float32Type, Float64Type:
- f, _ := n.Float()
- return strconv.FormatFloat(f, 'f', -1, 64)
- case IntType:
- i, _ := n.Int()
- return strconv.FormatInt(i, 10)
- case UintType:
- u, _ := n.Uint()
- return strconv.FormatUint(u, 10)
- default:
- panic("(*Number).typ is invalid")
- }
- }
|